• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1namespace ts {
2    export function findConfigFile(searchPath: string, fileExists: (fileName: string) => boolean, configName = "tsconfig.json"): string | undefined {
3        return forEachAncestorDirectory(searchPath, ancestor => {
4            const fileName = combinePaths(ancestor, configName);
5            return fileExists(fileName) ? fileName : undefined;
6        });
7    }
8
9    export function resolveTripleslashReference(moduleName: string, containingFile: string): string {
10        const basePath = getDirectoryPath(containingFile);
11        const referencedFileName = isRootedDiskPath(moduleName) ? moduleName : combinePaths(basePath, moduleName);
12        return normalizePath(referencedFileName);
13    }
14
15    /* @internal */
16    export function computeCommonSourceDirectoryOfFilenames(fileNames: readonly string[], currentDirectory: string, getCanonicalFileName: GetCanonicalFileName): string {
17        let commonPathComponents: string[] | undefined;
18        const failed = forEach(fileNames, sourceFile => {
19            // Each file contributes into common source file path
20            const sourcePathComponents = getNormalizedPathComponents(sourceFile, currentDirectory);
21            sourcePathComponents.pop(); // The base file name is not part of the common directory path
22
23            if (!commonPathComponents) {
24                // first file
25                commonPathComponents = sourcePathComponents;
26                return;
27            }
28
29            const n = Math.min(commonPathComponents.length, sourcePathComponents.length);
30            for (let i = 0; i < n; i++) {
31                if (getCanonicalFileName(commonPathComponents[i]) !== getCanonicalFileName(sourcePathComponents[i])) {
32                    if (i === 0) {
33                        // Failed to find any common path component
34                        return true;
35                    }
36
37                    // New common path found that is 0 -> i-1
38                    commonPathComponents.length = i;
39                    break;
40                }
41            }
42
43            // If the sourcePathComponents was shorter than the commonPathComponents, truncate to the sourcePathComponents
44            if (sourcePathComponents.length < commonPathComponents.length) {
45                commonPathComponents.length = sourcePathComponents.length;
46            }
47        });
48
49        // A common path can not be found when paths span multiple drives on windows, for example
50        if (failed) {
51            return "";
52        }
53
54        if (!commonPathComponents) { // Can happen when all input files are .d.ts files
55            return currentDirectory;
56        }
57
58        return getPathFromPathComponents(commonPathComponents);
59    }
60
61    export function createCompilerHost(options: CompilerOptions, setParentNodes?: boolean): CompilerHost {
62        return createCompilerHostWorker(options, setParentNodes);
63    }
64
65    /*@internal*/
66    export function createCompilerHostWorker(options: CompilerOptions, setParentNodes?: boolean, system = sys): CompilerHost {
67        const existingDirectories = new Map<string, boolean>();
68        const getCanonicalFileName = createGetCanonicalFileName(system.useCaseSensitiveFileNames);
69        function getSourceFile(fileName: string, languageVersionOrOptions: ScriptTarget | CreateSourceFileOptions, onError?: (message: string) => void): SourceFile | undefined {
70            let text: string | undefined;
71            try {
72                performance.mark("beforeIORead");
73                text = compilerHost.readFile(fileName);
74                performance.mark("afterIORead");
75                performance.measure("I/O Read", "beforeIORead", "afterIORead");
76            }
77            catch (e) {
78                if (onError) {
79                    onError(e.message);
80                }
81                text = "";
82            }
83            return text !== undefined ? createSourceFile(fileName, text, languageVersionOrOptions, setParentNodes, /*scriptKind*/ undefined, options) : undefined;
84        }
85
86        function directoryExists(directoryPath: string): boolean {
87            if (existingDirectories.has(directoryPath)) {
88                return true;
89            }
90            if ((compilerHost.directoryExists || system.directoryExists)(directoryPath)) {
91                existingDirectories.set(directoryPath, true);
92                return true;
93            }
94            return false;
95        }
96
97        function writeFile(fileName: string, data: string, writeByteOrderMark: boolean, onError?: (message: string) => void) {
98            try {
99                performance.mark("beforeIOWrite");
100
101                // NOTE: If patchWriteFileEnsuringDirectory has been called,
102                // the system.writeFile will do its own directory creation and
103                // the ensureDirectoriesExist call will always be redundant.
104                writeFileEnsuringDirectories(
105                    fileName,
106                    data,
107                    writeByteOrderMark,
108                    (path, data, writeByteOrderMark) => system.writeFile(path, data, writeByteOrderMark),
109                    path => (compilerHost.createDirectory || system.createDirectory)(path),
110                    path => directoryExists(path));
111
112                performance.mark("afterIOWrite");
113                performance.measure("I/O Write", "beforeIOWrite", "afterIOWrite");
114            }
115            catch (e) {
116                if (onError) {
117                    onError(e.message);
118                }
119            }
120        }
121
122        function getDefaultLibLocation(): string {
123            return getDirectoryPath(normalizePath(system.getExecutingFilePath()));
124        }
125
126        const newLine = getNewLineCharacter(options, () => system.newLine);
127        const realpath = system.realpath && ((path: string) => system.realpath!(path));
128        const compilerHost: CompilerHost = {
129            getSourceFile,
130            getDefaultLibLocation,
131            getDefaultLibFileName: options => combinePaths(getDefaultLibLocation(), getDefaultLibFileName(options)),
132            writeFile,
133            getCurrentDirectory: memoize(() => system.getCurrentDirectory()),
134            useCaseSensitiveFileNames: () => system.useCaseSensitiveFileNames,
135            getCanonicalFileName,
136            getNewLine: () => newLine,
137            fileExists: fileName => system.fileExists(fileName),
138            readFile: fileName => system.readFile(fileName),
139            trace: (s: string) => system.write(s + newLine),
140            directoryExists: directoryName => system.directoryExists(directoryName),
141            getEnvironmentVariable: name => system.getEnvironmentVariable ? system.getEnvironmentVariable(name) : "",
142            getDirectories: (path: string) => system.getDirectories(path),
143            realpath,
144            readDirectory: (path, extensions, include, exclude, depth) => system.readDirectory(path, extensions, include, exclude, depth),
145            createDirectory: d => system.createDirectory(d),
146            createHash: maybeBind(system, system.createHash)
147        };
148        return compilerHost;
149    }
150
151    /*@internal*/
152    interface CompilerHostLikeForCache {
153        fileExists(fileName: string): boolean;
154        readFile(fileName: string, encoding?: string): string | undefined;
155        directoryExists?(directory: string): boolean;
156        createDirectory?(directory: string): void;
157        writeFile?: WriteFileCallback;
158    }
159
160    /*@internal*/
161    export function changeCompilerHostLikeToUseCache(
162        host: CompilerHostLikeForCache,
163        toPath: (fileName: string) => Path,
164        getSourceFile?: CompilerHost["getSourceFile"]
165    ) {
166        const originalReadFile = host.readFile;
167        const originalFileExists = host.fileExists;
168        const originalDirectoryExists = host.directoryExists;
169        const originalCreateDirectory = host.createDirectory;
170        const originalWriteFile = host.writeFile;
171        const readFileCache = new Map<Path, string | false>();
172        const fileExistsCache = new Map<Path, boolean>();
173        const directoryExistsCache = new Map<Path, boolean>();
174        const sourceFileCache = new Map<SourceFile["impliedNodeFormat"], ESMap<Path, SourceFile>>();
175
176        const readFileWithCache = (fileName: string): string | undefined => {
177            const key = toPath(fileName);
178            const value = readFileCache.get(key);
179            if (value !== undefined) return value !== false ? value : undefined;
180            return setReadFileCache(key, fileName);
181        };
182        const setReadFileCache = (key: Path, fileName: string) => {
183            const newValue = originalReadFile.call(host, fileName);
184            readFileCache.set(key, newValue !== undefined ? newValue : false);
185            return newValue;
186        };
187        host.readFile = fileName => {
188            const key = toPath(fileName);
189            const value = readFileCache.get(key);
190            if (value !== undefined) return value !== false ? value : undefined; // could be .d.ts from output
191            // Cache json or buildInfo
192            if (!fileExtensionIs(fileName, Extension.Json) && !isBuildInfoFile(fileName)) {
193                return originalReadFile.call(host, fileName);
194            }
195
196            return setReadFileCache(key, fileName);
197        };
198
199        const getSourceFileWithCache: CompilerHost["getSourceFile"] | undefined = getSourceFile ? (fileName, languageVersionOrOptions, onError, shouldCreateNewSourceFile) => {
200            const key = toPath(fileName);
201            const impliedNodeFormat: SourceFile["impliedNodeFormat"] = typeof languageVersionOrOptions === "object" ? languageVersionOrOptions.impliedNodeFormat : undefined;
202            const forImpliedNodeFormat = sourceFileCache.get(impliedNodeFormat);
203            const value = forImpliedNodeFormat?.get(key);
204            if (value) return value;
205
206            const sourceFile = getSourceFile(fileName, languageVersionOrOptions, onError, shouldCreateNewSourceFile);
207            if (sourceFile && (isDeclarationFileName(fileName) || fileExtensionIs(fileName, Extension.Json))) {
208                sourceFileCache.set(impliedNodeFormat, (forImpliedNodeFormat || new Map()).set(key, sourceFile));
209            }
210            return sourceFile;
211        } : undefined;
212
213        // fileExists for any kind of extension
214        host.fileExists = fileName => {
215            const key = toPath(fileName);
216            const value = fileExistsCache.get(key);
217            if (value !== undefined) return value;
218            const newValue = originalFileExists.call(host, fileName);
219            fileExistsCache.set(key, !!newValue);
220            return newValue;
221        };
222        if (originalWriteFile) {
223            host.writeFile = (fileName, data, ...rest) => {
224                const key = toPath(fileName);
225                fileExistsCache.delete(key);
226
227                const value = readFileCache.get(key);
228                if (value !== undefined && value !== data) {
229                    readFileCache.delete(key);
230                    sourceFileCache.forEach(map => map.delete(key));
231                }
232                else if (getSourceFileWithCache) {
233                    sourceFileCache.forEach(map => {
234                        const sourceFile = map.get(key);
235                        if (sourceFile && sourceFile.text !== data) {
236                            map.delete(key);
237                        }
238                    });
239                }
240                originalWriteFile.call(host, fileName, data, ...rest);
241            };
242        }
243
244        // directoryExists
245        if (originalDirectoryExists) {
246            host.directoryExists = directory => {
247                const key = toPath(directory);
248                const value = directoryExistsCache.get(key);
249                if (value !== undefined) return value;
250                const newValue = originalDirectoryExists.call(host, directory);
251                directoryExistsCache.set(key, !!newValue);
252                return newValue;
253            };
254
255            if (originalCreateDirectory) {
256                host.createDirectory = directory => {
257                    const key = toPath(directory);
258                    directoryExistsCache.delete(key);
259                    originalCreateDirectory.call(host, directory);
260                };
261            }
262        }
263
264        return {
265            originalReadFile,
266            originalFileExists,
267            originalDirectoryExists,
268            originalCreateDirectory,
269            originalWriteFile,
270            getSourceFileWithCache,
271            readFileWithCache
272        };
273    }
274
275    export function getPreEmitDiagnostics(program: Program, sourceFile?: SourceFile, cancellationToken?: CancellationToken): readonly Diagnostic[];
276    /*@internal*/ export function getPreEmitDiagnostics(program: BuilderProgram, sourceFile?: SourceFile, cancellationToken?: CancellationToken): readonly Diagnostic[]; // eslint-disable-line @typescript-eslint/unified-signatures
277    export function getPreEmitDiagnostics(program: Program | BuilderProgram, sourceFile?: SourceFile, cancellationToken?: CancellationToken): readonly Diagnostic[] {
278        let diagnostics: Diagnostic[] | undefined;
279        diagnostics = addRange(diagnostics, program.getConfigFileParsingDiagnostics());
280        diagnostics = addRange(diagnostics, program.getOptionsDiagnostics(cancellationToken));
281        diagnostics = addRange(diagnostics, program.getSyntacticDiagnostics(sourceFile, cancellationToken));
282        diagnostics = addRange(diagnostics, program.getGlobalDiagnostics(cancellationToken));
283        diagnostics = addRange(diagnostics, program.getSemanticDiagnostics(sourceFile, cancellationToken));
284
285        if (getEmitDeclarations(program.getCompilerOptions())) {
286            diagnostics = addRange(diagnostics, program.getDeclarationDiagnostics(sourceFile, cancellationToken));
287        }
288
289        return sortAndDeduplicateDiagnostics(diagnostics || emptyArray);
290    }
291
292    export interface FormatDiagnosticsHost {
293        getCurrentDirectory(): string;
294        getCanonicalFileName(fileName: string): string;
295        getNewLine(): string;
296    }
297
298    export function formatDiagnostics(diagnostics: readonly Diagnostic[], host: FormatDiagnosticsHost): string {
299        let output = "";
300
301        for (const diagnostic of diagnostics) {
302            output += formatDiagnostic(diagnostic, host);
303        }
304        return output;
305    }
306
307    export function formatDiagnostic(diagnostic: Diagnostic, host: FormatDiagnosticsHost): string {
308        const errorMessage = `${diagnosticCategoryName(diagnostic)} TS${diagnostic.code}: ${flattenDiagnosticMessageText(diagnostic.messageText, host.getNewLine())}${host.getNewLine()}`;
309
310        if (diagnostic.file) {
311            const { line, character } = getLineAndCharacterOfPosition(diagnostic.file, diagnostic.start!); // TODO: GH#18217
312            const fileName = diagnostic.file.fileName;
313            const relativeFileName = convertToRelativePath(fileName, host.getCurrentDirectory(), fileName => host.getCanonicalFileName(fileName));
314            return `${relativeFileName}(${line + 1},${character + 1}): ` + errorMessage;
315        }
316
317        return errorMessage;
318    }
319
320    /** @internal */
321    export enum ForegroundColorEscapeSequences {
322        Grey = "\u001b[90m",
323        Red = "\u001b[91m",
324        Yellow = "\u001b[93m",
325        Blue = "\u001b[94m",
326        Cyan = "\u001b[96m"
327    }
328    const gutterStyleSequence = "\u001b[7m";
329    const gutterSeparator = " ";
330    const resetEscapeSequence = "\u001b[0m";
331    const ellipsis = "...";
332    const halfIndent = "  ";
333    const indent = "    ";
334    function getCategoryFormat(category: DiagnosticCategory): ForegroundColorEscapeSequences {
335        switch (category) {
336            case DiagnosticCategory.Error: return ForegroundColorEscapeSequences.Red;
337            case DiagnosticCategory.Warning: return ForegroundColorEscapeSequences.Yellow;
338            case DiagnosticCategory.Suggestion: return Debug.fail("Should never get an Info diagnostic on the command line.");
339            case DiagnosticCategory.Message: return ForegroundColorEscapeSequences.Blue;
340        }
341    }
342
343    /** @internal */
344    export function formatColorAndReset(text: string, formatStyle: string) {
345        return formatStyle + text + resetEscapeSequence;
346    }
347
348    function formatCodeSpan(file: SourceFile, start: number, length: number, indent: string, squiggleColor: ForegroundColorEscapeSequences, host: FormatDiagnosticsHost) {
349        const { line: firstLine, character: firstLineChar } = getLineAndCharacterOfPosition(file, start);
350        const { line: lastLine, character: lastLineChar } = getLineAndCharacterOfPosition(file, start + length);
351        const lastLineInFile = getLineAndCharacterOfPosition(file, file.text.length).line;
352
353        const hasMoreThanFiveLines = (lastLine - firstLine) >= 4;
354        let gutterWidth = (lastLine + 1 + "").length;
355        if (hasMoreThanFiveLines) {
356            gutterWidth = Math.max(ellipsis.length, gutterWidth);
357        }
358
359        let context = "";
360        for (let i = firstLine; i <= lastLine; i++) {
361            context += host.getNewLine();
362            // If the error spans over 5 lines, we'll only show the first 2 and last 2 lines,
363            // so we'll skip ahead to the second-to-last line.
364            if (hasMoreThanFiveLines && firstLine + 1 < i && i < lastLine - 1) {
365                context += indent + formatColorAndReset(padLeft(ellipsis, gutterWidth), gutterStyleSequence) + gutterSeparator + host.getNewLine();
366                i = lastLine - 1;
367            }
368
369            const lineStart = getPositionOfLineAndCharacter(file, i, 0);
370            const lineEnd = i < lastLineInFile ? getPositionOfLineAndCharacter(file, i + 1, 0) : file.text.length;
371            let lineContent = file.text.slice(lineStart, lineEnd);
372            lineContent = trimStringEnd(lineContent);  // trim from end
373            lineContent = lineContent.replace(/\t/g, " ");   // convert tabs to single spaces
374
375            // Output the gutter and the actual contents of the line.
376            context += indent + formatColorAndReset(padLeft(i + 1 + "", gutterWidth), gutterStyleSequence) + gutterSeparator;
377            context += lineContent + host.getNewLine();
378
379            // Output the gutter and the error span for the line using tildes.
380            context += indent + formatColorAndReset(padLeft("", gutterWidth), gutterStyleSequence) + gutterSeparator;
381            context += squiggleColor;
382            if (i === firstLine) {
383                // If we're on the last line, then limit it to the last character of the last line.
384                // Otherwise, we'll just squiggle the rest of the line, giving 'slice' no end position.
385                const lastCharForLine = i === lastLine ? lastLineChar : undefined;
386
387                context += lineContent.slice(0, firstLineChar).replace(/\S/g, " ");
388                context += lineContent.slice(firstLineChar, lastCharForLine).replace(/./g, "~");
389            }
390            else if (i === lastLine) {
391                context += lineContent.slice(0, lastLineChar).replace(/./g, "~");
392            }
393            else {
394                // Squiggle the entire line.
395                context += lineContent.replace(/./g, "~");
396            }
397            context += resetEscapeSequence;
398        }
399        return context;
400    }
401
402    /* @internal */
403    export function formatLocation(file: SourceFile, start: number, host: FormatDiagnosticsHost, color = formatColorAndReset) {
404        const { line: firstLine, character: firstLineChar } = getLineAndCharacterOfPosition(file, start); // TODO: GH#18217
405        const relativeFileName = host ? convertToRelativePath(file.fileName, host.getCurrentDirectory(), fileName => host.getCanonicalFileName(fileName)) : file.fileName;
406
407        let output = "";
408        output += color(relativeFileName, ForegroundColorEscapeSequences.Cyan);
409        output += ":";
410        output += color(`${firstLine + 1}`, ForegroundColorEscapeSequences.Yellow);
411        output += ":";
412        output += color(`${firstLineChar + 1}`, ForegroundColorEscapeSequences.Yellow);
413        return output;
414    }
415
416    export function formatDiagnosticsWithColorAndContext(diagnostics: readonly Diagnostic[], host: FormatDiagnosticsHost): string {
417        let output = "";
418        for (const diagnostic of diagnostics) {
419            if (diagnostic.file) {
420                const { file, start } = diagnostic;
421                output += formatLocation(file, start!, host); // TODO: GH#18217
422                output += " - ";
423            }
424
425            output += formatColorAndReset(diagnosticCategoryName(diagnostic), getCategoryFormat(diagnostic.category));
426            output += formatColorAndReset(` TS${diagnostic.code}: `, ForegroundColorEscapeSequences.Grey);
427            output += flattenDiagnosticMessageText(diagnostic.messageText, host.getNewLine());
428
429            if (diagnostic.file) {
430                output += host.getNewLine();
431                output += formatCodeSpan(diagnostic.file, diagnostic.start!, diagnostic.length!, "", getCategoryFormat(diagnostic.category), host); // TODO: GH#18217
432            }
433            if (diagnostic.relatedInformation) {
434                output += host.getNewLine();
435                for (const { file, start, length, messageText } of diagnostic.relatedInformation) {
436                    if (file) {
437                        output += host.getNewLine();
438                        output += halfIndent + formatLocation(file, start!, host); // TODO: GH#18217
439                        output += formatCodeSpan(file, start!, length!, indent, ForegroundColorEscapeSequences.Cyan, host); // TODO: GH#18217
440                    }
441                    output += host.getNewLine();
442                    output += indent + flattenDiagnosticMessageText(messageText, host.getNewLine());
443                }
444            }
445            output += host.getNewLine();
446        }
447        return output;
448    }
449
450    export function flattenDiagnosticMessageText(diag: string | DiagnosticMessageChain | undefined, newLine: string, indent = 0): string {
451        if (isString(diag)) {
452            return diag;
453        }
454        else if (diag === undefined) {
455            return "";
456        }
457        let result = "";
458        if (indent) {
459            result += newLine;
460
461            for (let i = 0; i < indent; i++) {
462                result += "  ";
463            }
464        }
465        result += diag.messageText;
466        indent++;
467        if (diag.next) {
468            for (const kid of diag.next) {
469                result += flattenDiagnosticMessageText(kid, newLine, indent);
470            }
471        }
472        return result;
473    }
474
475    /* @internal */
476    export function loadWithTypeDirectiveCache<T>(names: string[] | readonly FileReference[], containingFile: string, redirectedReference: ResolvedProjectReference | undefined, containingFileMode: SourceFile["impliedNodeFormat"], loader: (name: string, containingFile: string, redirectedReference: ResolvedProjectReference | undefined, resolutionMode: SourceFile["impliedNodeFormat"]) => T): T[] {
477        if (names.length === 0) {
478            return [];
479        }
480        const resolutions: T[] = [];
481        const cache = new Map<string, T>();
482        for (const name of names) {
483            let result: T;
484            const mode = getModeForFileReference(name, containingFileMode);
485            // We lower-case all type references because npm automatically lowercases all packages. See GH#9824.
486            const strName = isString(name) ? name : name.fileName.toLowerCase();
487            const cacheKey = mode !== undefined ? `${mode}|${strName}` : strName;
488            if (cache.has(cacheKey)) {
489                result = cache.get(cacheKey)!;
490            }
491            else {
492                cache.set(cacheKey, result = loader(strName, containingFile, redirectedReference, mode));
493            }
494            resolutions.push(result);
495        }
496        return resolutions;
497    }
498
499    /**
500     * Subset of a SourceFile used to calculate index-based resolutions
501     * This includes some internal fields, so unless you have very good reason,
502     * (and are willing to use some less stable internals) you should probably just pass a SourceFile.
503     *
504     * @internal
505     */
506    export interface SourceFileImportsList {
507        /* @internal */ imports: SourceFile["imports"];
508        /* @internal */ moduleAugmentations: SourceFile["moduleAugmentations"];
509        impliedNodeFormat?: SourceFile["impliedNodeFormat"];
510    }
511
512    /**
513     * Calculates the resulting resolution mode for some reference in some file - this is generally the explicitly
514     * provided resolution mode in the reference, unless one is not present, in which case it is the mode of the containing file.
515     */
516    export function getModeForFileReference(ref: FileReference | string, containingFileMode: SourceFile["impliedNodeFormat"]) {
517        return (isString(ref) ? containingFileMode : ref.resolutionMode) || containingFileMode;
518    }
519
520    /**
521     * Calculates the final resolution mode for an import at some index within a file's imports list. This is generally the explicitly
522     * defined mode of the import if provided, or, if not, the mode of the containing file (with some exceptions: import=require is always commonjs, dynamic import is always esm).
523     * If you have an actual import node, prefer using getModeForUsageLocation on the reference string node.
524     * @param file File to fetch the resolution mode within
525     * @param index Index into the file's complete resolution list to get the resolution of - this is a concatenation of the file's imports and module augmentations
526     */
527    export function getModeForResolutionAtIndex(file: SourceFile, index: number): ModuleKind.CommonJS | ModuleKind.ESNext | undefined;
528    /** @internal */
529    // eslint-disable-next-line @typescript-eslint/unified-signatures
530    export function getModeForResolutionAtIndex(file: SourceFileImportsList, index: number): ModuleKind.CommonJS | ModuleKind.ESNext | undefined;
531    export function getModeForResolutionAtIndex(file: SourceFileImportsList, index: number): ModuleKind.CommonJS | ModuleKind.ESNext | undefined {
532        if (file.impliedNodeFormat === undefined) return undefined;
533        // we ensure all elements of file.imports and file.moduleAugmentations have the relevant parent pointers set during program setup,
534        // so it's safe to use them even pre-bind
535        return getModeForUsageLocation(file, getModuleNameStringLiteralAt(file, index));
536    }
537
538    /* @internal */
539    export function isExclusivelyTypeOnlyImportOrExport(decl: ImportDeclaration | ExportDeclaration) {
540        if (isExportDeclaration(decl)) {
541            return decl.isTypeOnly;
542        }
543        if (decl.importClause?.isTypeOnly) {
544            return true;
545        }
546        return false;
547    }
548
549    /**
550     * Calculates the final resolution mode for a given module reference node. This is generally the explicitly provided resolution mode, if
551     * one exists, or the mode of the containing source file. (Excepting import=require, which is always commonjs, and dynamic import, which is always esm).
552     * Notably, this function always returns `undefined` if the containing file has an `undefined` `impliedNodeFormat` - this field is only set when
553     * `moduleResolution` is `node16`+.
554     * @param file The file the import or import-like reference is contained within
555     * @param usage The module reference string
556     * @returns The final resolution mode of the import
557     */
558    export function getModeForUsageLocation(file: {impliedNodeFormat?: SourceFile["impliedNodeFormat"]}, usage: StringLiteralLike) {
559        if (file.impliedNodeFormat === undefined) return undefined;
560        if ((isImportDeclaration(usage.parent) || isExportDeclaration(usage.parent))) {
561            const isTypeOnly = isExclusivelyTypeOnlyImportOrExport(usage.parent);
562            if (isTypeOnly) {
563                const override = getResolutionModeOverrideForClause(usage.parent.assertClause);
564                if (override) {
565                    return override;
566                }
567            }
568        }
569        if (usage.parent.parent && isImportTypeNode(usage.parent.parent)) {
570            const override = getResolutionModeOverrideForClause(usage.parent.parent.assertions?.assertClause);
571            if (override) {
572                return override;
573            }
574        }
575        if (file.impliedNodeFormat !== ModuleKind.ESNext) {
576            // in cjs files, import call expressions are esm format, otherwise everything is cjs
577            return isImportCall(walkUpParenthesizedExpressions(usage.parent)) ? ModuleKind.ESNext : ModuleKind.CommonJS;
578        }
579        // in esm files, import=require statements are cjs format, otherwise everything is esm
580        // imports are only parent'd up to their containing declaration/expression, so access farther parents with care
581        const exprParentParent = walkUpParenthesizedExpressions(usage.parent)?.parent;
582        return exprParentParent && isImportEqualsDeclaration(exprParentParent) ? ModuleKind.CommonJS : ModuleKind.ESNext;
583    }
584
585    /* @internal */
586    export function getResolutionModeOverrideForClause(clause: AssertClause | undefined, grammarErrorOnNode?: (node: Node, diagnostic: DiagnosticMessage) => void) {
587        if (!clause) return undefined;
588        if (length(clause.elements) !== 1) {
589            grammarErrorOnNode?.(clause, Diagnostics.Type_import_assertions_should_have_exactly_one_key_resolution_mode_with_value_import_or_require);
590            return undefined;
591        }
592        const elem = clause.elements[0];
593        if (!isStringLiteralLike(elem.name)) return undefined;
594        if (elem.name.text !== "resolution-mode") {
595            grammarErrorOnNode?.(elem.name, Diagnostics.resolution_mode_is_the_only_valid_key_for_type_import_assertions);
596            return undefined;
597        }
598        if (!isStringLiteralLike(elem.value)) return undefined;
599        if (elem.value.text !== "import" && elem.value.text !== "require") {
600            grammarErrorOnNode?.(elem.value, Diagnostics.resolution_mode_should_be_either_require_or_import);
601            return undefined;
602        }
603        return elem.value.text === "import" ? ModuleKind.ESNext : ModuleKind.CommonJS;
604    }
605
606    /* @internal */
607    export function loadWithModeAwareCache<T>(names: string[], containingFile: SourceFile, containingFileName: string, redirectedReference: ResolvedProjectReference | undefined, loader: (name: string, resolverMode: ModuleKind.CommonJS | ModuleKind.ESNext | undefined, containingFileName: string, redirectedReference: ResolvedProjectReference | undefined) => T): T[] {
608        if (names.length === 0) {
609            return [];
610        }
611        const resolutions: T[] = [];
612        const cache = new Map<string, T>();
613        let i = 0;
614        for (const name of names) {
615            let result: T;
616            const mode = getModeForResolutionAtIndex(containingFile, i);
617            i++;
618            const cacheKey = mode !== undefined ? `${mode}|${name}` : name;
619            if (cache.has(cacheKey)) {
620                result = cache.get(cacheKey)!;
621            }
622            else {
623                cache.set(cacheKey, result = loader(name, mode, containingFileName, redirectedReference));
624            }
625            resolutions.push(result);
626        }
627        return resolutions;
628    }
629
630    /* @internal */
631    export function forEachResolvedProjectReference<T>(
632        resolvedProjectReferences: readonly (ResolvedProjectReference | undefined)[] | undefined,
633        cb: (resolvedProjectReference: ResolvedProjectReference, parent: ResolvedProjectReference | undefined) => T | undefined
634    ): T | undefined {
635        return forEachProjectReference(/*projectReferences*/ undefined, resolvedProjectReferences, (resolvedRef, parent) => resolvedRef && cb(resolvedRef, parent));
636    }
637
638    function forEachProjectReference<T>(
639        projectReferences: readonly ProjectReference[] | undefined,
640        resolvedProjectReferences: readonly (ResolvedProjectReference | undefined)[] | undefined,
641        cbResolvedRef: (resolvedRef: ResolvedProjectReference | undefined, parent: ResolvedProjectReference | undefined, index: number) => T | undefined,
642        cbRef?: (projectReferences: readonly ProjectReference[] | undefined, parent: ResolvedProjectReference | undefined) => T | undefined
643    ): T | undefined {
644        let seenResolvedRefs: Set<Path> | undefined;
645
646        return worker(projectReferences, resolvedProjectReferences, /*parent*/ undefined);
647
648        function worker(
649            projectReferences: readonly ProjectReference[] | undefined,
650            resolvedProjectReferences: readonly (ResolvedProjectReference | undefined)[] | undefined,
651            parent: ResolvedProjectReference | undefined,
652        ): T | undefined {
653
654            // Visit project references first
655            if (cbRef) {
656                const result = cbRef(projectReferences, parent);
657                if (result) return result;
658            }
659
660            return forEach(resolvedProjectReferences, (resolvedRef, index) => {
661                if (resolvedRef && seenResolvedRefs?.has(resolvedRef.sourceFile.path)) {
662                    // ignore recursives
663                    return undefined;
664                }
665
666                const result = cbResolvedRef(resolvedRef, parent, index);
667                if (result || !resolvedRef) return result;
668
669                (seenResolvedRefs ||= new Set()).add(resolvedRef.sourceFile.path);
670                return worker(resolvedRef.commandLine.projectReferences, resolvedRef.references, resolvedRef);
671            });
672        }
673    }
674
675    /* @internal */
676    export const inferredTypesContainingFile = "__inferred type names__.ts";
677
678    interface DiagnosticCache<T extends Diagnostic> {
679        perFile?: ESMap<Path, readonly T[]>;
680        allDiagnostics?: readonly T[];
681    }
682
683    /*@internal*/
684    export function isReferencedFile(reason: FileIncludeReason | undefined): reason is ReferencedFile {
685        switch (reason?.kind) {
686            case FileIncludeKind.Import:
687            case FileIncludeKind.ReferenceFile:
688            case FileIncludeKind.TypeReferenceDirective:
689            case FileIncludeKind.LibReferenceDirective:
690                return true;
691            default:
692                return false;
693        }
694    }
695
696    /*@internal*/
697    export interface ReferenceFileLocation {
698        file: SourceFile;
699        pos: number;
700        end: number;
701        packageId: PackageId | undefined;
702    }
703
704    /*@internal*/
705    export interface SyntheticReferenceFileLocation {
706        file: SourceFile;
707        packageId: PackageId | undefined;
708        text: string;
709    }
710
711    /*@internal*/
712    export function isReferenceFileLocation(location: ReferenceFileLocation | SyntheticReferenceFileLocation): location is ReferenceFileLocation {
713        return (location as ReferenceFileLocation).pos !== undefined;
714    }
715
716    /*@internal*/
717    export function getReferencedFileLocation(getSourceFileByPath: (path: Path) => SourceFile | undefined, ref: ReferencedFile): ReferenceFileLocation | SyntheticReferenceFileLocation {
718        const file = Debug.checkDefined(getSourceFileByPath(ref.file));
719        const { kind, index } = ref;
720        let pos: number | undefined, end: number | undefined, packageId: PackageId | undefined, resolutionMode: FileReference["resolutionMode"] | undefined;
721        switch (kind) {
722            case FileIncludeKind.Import:
723                const importLiteral = getModuleNameStringLiteralAt(file, index);
724                packageId = file.resolvedModules?.get(importLiteral.text, getModeForResolutionAtIndex(file, index))?.packageId;
725                if (importLiteral.pos === -1) return { file, packageId, text: importLiteral.text };
726                pos = skipTrivia(file.text, importLiteral.pos);
727                end = importLiteral.end;
728                break;
729            case FileIncludeKind.ReferenceFile:
730                ({ pos, end } = file.referencedFiles[index]);
731                break;
732            case FileIncludeKind.TypeReferenceDirective:
733                ({ pos, end, resolutionMode } = file.typeReferenceDirectives[index]);
734                packageId = file.resolvedTypeReferenceDirectiveNames?.get(toFileNameLowerCase(file.typeReferenceDirectives[index].fileName), resolutionMode || file.impliedNodeFormat)?.packageId;
735                break;
736            case FileIncludeKind.LibReferenceDirective:
737                ({ pos, end } = file.libReferenceDirectives[index]);
738                break;
739            default:
740                return Debug.assertNever(kind);
741        }
742        return { file, pos, end, packageId };
743    }
744
745    /**
746     * Determines if program structure is upto date or needs to be recreated
747     */
748    /* @internal */
749    export function isProgramUptoDate(
750        program: Program | undefined,
751        rootFileNames: string[],
752        newOptions: CompilerOptions,
753        getSourceVersion: (path: Path, fileName: string) => string | undefined,
754        fileExists: (fileName: string) => boolean,
755        hasInvalidatedResolutions: HasInvalidatedResolutions,
756        hasChangedAutomaticTypeDirectiveNames: HasChangedAutomaticTypeDirectiveNames | undefined,
757        getParsedCommandLine: (fileName: string) => ParsedCommandLine | undefined,
758        projectReferences: readonly ProjectReference[] | undefined
759    ): boolean {
760        // If we haven't created a program yet or have changed automatic type directives, then it is not up-to-date
761        if (!program || hasChangedAutomaticTypeDirectiveNames?.()) return false;
762
763        // If root file names don't match
764        if (!arrayIsEqualTo(program.getRootFileNames(), rootFileNames)) return false;
765
766        let seenResolvedRefs: ResolvedProjectReference[] | undefined;
767
768        // If project references don't match
769        if (!arrayIsEqualTo(program.getProjectReferences(), projectReferences, projectReferenceUptoDate)) return false;
770
771        // If any file is not up-to-date, then the whole program is not up-to-date
772        if (program.getSourceFiles().some(sourceFileNotUptoDate)) return false;
773
774        // If any of the missing file paths are now created
775        if (program.getMissingFilePaths().some(fileExists)) return false;
776
777        const currentOptions = program.getCompilerOptions();
778        // If the compilation settings do no match, then the program is not up-to-date
779        if (!compareDataObjects(currentOptions, newOptions)) return false;
780
781        // If everything matches but the text of config file is changed,
782        // error locations can change for program options, so update the program
783        if (currentOptions.configFile && newOptions.configFile) return currentOptions.configFile.text === newOptions.configFile.text;
784
785        return true;
786
787        function sourceFileNotUptoDate(sourceFile: SourceFile) {
788            return !sourceFileVersionUptoDate(sourceFile) ||
789                hasInvalidatedResolutions(sourceFile.path);
790        }
791
792        function sourceFileVersionUptoDate(sourceFile: SourceFile) {
793            return sourceFile.version === getSourceVersion(sourceFile.resolvedPath, sourceFile.fileName);
794        }
795
796        function projectReferenceUptoDate(oldRef: ProjectReference, newRef: ProjectReference, index: number) {
797            return projectReferenceIsEqualTo(oldRef, newRef) &&
798                resolvedProjectReferenceUptoDate(program!.getResolvedProjectReferences()![index], oldRef);
799        }
800
801        function resolvedProjectReferenceUptoDate(oldResolvedRef: ResolvedProjectReference | undefined, oldRef: ProjectReference): boolean {
802            if (oldResolvedRef) {
803                    // Assume true
804                if (contains(seenResolvedRefs, oldResolvedRef)) return true;
805
806                const refPath = resolveProjectReferencePath(oldRef);
807                const newParsedCommandLine = getParsedCommandLine(refPath);
808
809                // Check if config file exists
810                if (!newParsedCommandLine) return false;
811
812                // If change in source file
813                if (oldResolvedRef.commandLine.options.configFile !== newParsedCommandLine.options.configFile) return false;
814
815                // check file names
816                if (!arrayIsEqualTo(oldResolvedRef.commandLine.fileNames, newParsedCommandLine.fileNames)) return false;
817
818                // Add to seen before checking the referenced paths of this config file
819                (seenResolvedRefs || (seenResolvedRefs = [])).push(oldResolvedRef);
820
821                // If child project references are upto date, this project reference is uptodate
822                return !forEach(oldResolvedRef.references, (childResolvedRef, index) =>
823                    !resolvedProjectReferenceUptoDate(childResolvedRef, oldResolvedRef.commandLine.projectReferences![index]));
824            }
825
826            // In old program, not able to resolve project reference path,
827            // so if config file doesnt exist, it is uptodate.
828            const refPath = resolveProjectReferencePath(oldRef);
829            return !getParsedCommandLine(refPath);
830        }
831    }
832
833    export function getConfigFileParsingDiagnostics(configFileParseResult: ParsedCommandLine): readonly Diagnostic[] {
834        return configFileParseResult.options.configFile ?
835            [...configFileParseResult.options.configFile.parseDiagnostics, ...configFileParseResult.errors] :
836            configFileParseResult.errors;
837    }
838
839    /**
840     * A function for determining if a given file is esm or cjs format, assuming modern node module resolution rules, as configured by the
841     * `options` parameter.
842     *
843     * @param fileName The normalized absolute path to check the format of (it need not exist on disk)
844     * @param [packageJsonInfoCache] A cache for package file lookups - it's best to have a cache when this function is called often
845     * @param host The ModuleResolutionHost which can perform the filesystem lookups for package json data
846     * @param options The compiler options to perform the analysis under - relevant options are `moduleResolution` and `traceResolution`
847     * @returns `undefined` if the path has no relevant implied format, `ModuleKind.ESNext` for esm format, and `ModuleKind.CommonJS` for cjs format
848     */
849    export function getImpliedNodeFormatForFile(fileName: Path, packageJsonInfoCache: PackageJsonInfoCache | undefined, host: ModuleResolutionHost, options: CompilerOptions): ModuleKind.ESNext | ModuleKind.CommonJS | undefined {
850        const result = getImpliedNodeFormatForFileWorker(fileName, packageJsonInfoCache, host, options);
851        return typeof result === "object" ? result.impliedNodeFormat : result;
852    }
853
854    /*@internal*/
855    export function getImpliedNodeFormatForFileWorker(
856        fileName: string,
857        packageJsonInfoCache: PackageJsonInfoCache | undefined,
858        host: ModuleResolutionHost,
859        options: CompilerOptions,
860    ) {
861        switch (getEmitModuleResolutionKind(options)) {
862            case ModuleResolutionKind.Node16:
863            case ModuleResolutionKind.NodeNext:
864                return fileExtensionIsOneOf(fileName, [Extension.Dmts, Extension.Mts, Extension.Mjs]) ? ModuleKind.ESNext :
865                    fileExtensionIsOneOf(fileName, [Extension.Dcts, Extension.Cts, Extension.Cjs]) ? ModuleKind.CommonJS :
866                    fileExtensionIsOneOf(fileName, [Extension.Dts, Extension.Ts, Extension.Tsx, Extension.Js, Extension.Jsx]) ? lookupFromPackageJson() :
867                    undefined; // other extensions, like `json` or `tsbuildinfo`, are set as `undefined` here but they should never be fed through the transformer pipeline
868            default:
869                return undefined;
870        }
871        function lookupFromPackageJson(): Partial<CreateSourceFileOptions> {
872            const state = getTemporaryModuleResolutionState(packageJsonInfoCache, host, options);
873            const packageJsonLocations: string[] = [];
874            state.failedLookupLocations = packageJsonLocations;
875            state.affectingLocations = packageJsonLocations;
876            const packageJsonScope = getPackageScopeForPath(fileName, state);
877            const impliedNodeFormat = packageJsonScope?.contents.packageJsonContent.type === "module" ? ModuleKind.ESNext : ModuleKind.CommonJS;
878            return { impliedNodeFormat, packageJsonLocations, packageJsonScope };
879        }
880    }
881
882    /** @internal */
883    export const plainJSErrors: Set<number> = new Set([
884        // binder errors
885        Diagnostics.Cannot_redeclare_block_scoped_variable_0.code,
886        Diagnostics.A_module_cannot_have_multiple_default_exports.code,
887        Diagnostics.Another_export_default_is_here.code,
888        Diagnostics.The_first_export_default_is_here.code,
889        Diagnostics.Identifier_expected_0_is_a_reserved_word_at_the_top_level_of_a_module.code,
890        Diagnostics.Identifier_expected_0_is_a_reserved_word_in_strict_mode_Modules_are_automatically_in_strict_mode.code,
891        Diagnostics.Identifier_expected_0_is_a_reserved_word_that_cannot_be_used_here.code,
892        Diagnostics.constructor_is_a_reserved_word.code,
893        Diagnostics.delete_cannot_be_called_on_an_identifier_in_strict_mode.code,
894        Diagnostics.Code_contained_in_a_class_is_evaluated_in_JavaScript_s_strict_mode_which_does_not_allow_this_use_of_0_For_more_information_see_https_Colon_Slash_Slashdeveloper_mozilla_org_Slashen_US_Slashdocs_SlashWeb_SlashJavaScript_SlashReference_SlashStrict_mode.code,
895        Diagnostics.Invalid_use_of_0_Modules_are_automatically_in_strict_mode.code,
896        Diagnostics.Invalid_use_of_0_in_strict_mode.code,
897        Diagnostics.A_label_is_not_allowed_here.code,
898        Diagnostics.Octal_literals_are_not_allowed_in_strict_mode.code,
899        Diagnostics.with_statements_are_not_allowed_in_strict_mode.code,
900        // grammar errors
901        Diagnostics.A_break_statement_can_only_be_used_within_an_enclosing_iteration_or_switch_statement.code,
902        Diagnostics.A_break_statement_can_only_jump_to_a_label_of_an_enclosing_statement.code,
903        Diagnostics.A_class_declaration_without_the_default_modifier_must_have_a_name.code,
904        Diagnostics.A_class_member_cannot_have_the_0_keyword.code,
905        Diagnostics.A_comma_expression_is_not_allowed_in_a_computed_property_name.code,
906        Diagnostics.A_continue_statement_can_only_be_used_within_an_enclosing_iteration_statement.code,
907        Diagnostics.A_continue_statement_can_only_jump_to_a_label_of_an_enclosing_iteration_statement.code,
908        Diagnostics.A_continue_statement_can_only_jump_to_a_label_of_an_enclosing_iteration_statement.code,
909        Diagnostics.A_default_clause_cannot_appear_more_than_once_in_a_switch_statement.code,
910        Diagnostics.A_default_export_must_be_at_the_top_level_of_a_file_or_module_declaration.code,
911        Diagnostics.A_definite_assignment_assertion_is_not_permitted_in_this_context.code,
912        Diagnostics.A_destructuring_declaration_must_have_an_initializer.code,
913        Diagnostics.A_get_accessor_cannot_have_parameters.code,
914        Diagnostics.A_rest_element_cannot_contain_a_binding_pattern.code,
915        Diagnostics.A_rest_element_cannot_have_a_property_name.code,
916        Diagnostics.A_rest_element_cannot_have_an_initializer.code,
917        Diagnostics.A_rest_element_must_be_last_in_a_destructuring_pattern.code,
918        Diagnostics.A_rest_parameter_cannot_have_an_initializer.code,
919        Diagnostics.A_rest_parameter_must_be_last_in_a_parameter_list.code,
920        Diagnostics.A_rest_parameter_or_binding_pattern_may_not_have_a_trailing_comma.code,
921        Diagnostics.A_return_statement_cannot_be_used_inside_a_class_static_block.code,
922        Diagnostics.A_set_accessor_cannot_have_rest_parameter.code,
923        Diagnostics.A_set_accessor_must_have_exactly_one_parameter.code,
924        Diagnostics.An_export_declaration_can_only_be_used_at_the_top_level_of_a_module.code,
925        Diagnostics.An_export_declaration_cannot_have_modifiers.code,
926        Diagnostics.An_import_declaration_can_only_be_used_at_the_top_level_of_a_module.code,
927        Diagnostics.An_import_declaration_cannot_have_modifiers.code,
928        Diagnostics.An_object_member_cannot_be_declared_optional.code,
929        Diagnostics.Argument_of_dynamic_import_cannot_be_spread_element.code,
930        Diagnostics.Cannot_assign_to_private_method_0_Private_methods_are_not_writable.code,
931        Diagnostics.Cannot_redeclare_identifier_0_in_catch_clause.code,
932        Diagnostics.Catch_clause_variable_cannot_have_an_initializer.code,
933        Diagnostics.Class_decorators_can_t_be_used_with_static_private_identifier_Consider_removing_the_experimental_decorator.code,
934        Diagnostics.Classes_can_only_extend_a_single_class.code,
935        Diagnostics.Classes_may_not_have_a_field_named_constructor.code,
936        Diagnostics.Did_you_mean_to_use_a_Colon_An_can_only_follow_a_property_name_when_the_containing_object_literal_is_part_of_a_destructuring_pattern.code,
937        Diagnostics.Duplicate_label_0.code,
938        Diagnostics.Dynamic_imports_can_only_accept_a_module_specifier_and_an_optional_assertion_as_arguments.code,
939        Diagnostics.For_await_loops_cannot_be_used_inside_a_class_static_block.code,
940        Diagnostics.JSX_attributes_must_only_be_assigned_a_non_empty_expression.code,
941        Diagnostics.JSX_elements_cannot_have_multiple_attributes_with_the_same_name.code,
942        Diagnostics.JSX_expressions_may_not_use_the_comma_operator_Did_you_mean_to_write_an_array.code,
943        Diagnostics.JSX_property_access_expressions_cannot_include_JSX_namespace_names.code,
944        Diagnostics.Jump_target_cannot_cross_function_boundary.code,
945        Diagnostics.Line_terminator_not_permitted_before_arrow.code,
946        Diagnostics.Modifiers_cannot_appear_here.code,
947        Diagnostics.Only_a_single_variable_declaration_is_allowed_in_a_for_in_statement.code,
948        Diagnostics.Only_a_single_variable_declaration_is_allowed_in_a_for_of_statement.code,
949        Diagnostics.Private_identifiers_are_not_allowed_outside_class_bodies.code,
950        Diagnostics.Private_identifiers_are_only_allowed_in_class_bodies_and_may_only_be_used_as_part_of_a_class_member_declaration_property_access_or_on_the_left_hand_side_of_an_in_expression.code,
951        Diagnostics.Property_0_is_not_accessible_outside_class_1_because_it_has_a_private_identifier.code,
952        Diagnostics.Tagged_template_expressions_are_not_permitted_in_an_optional_chain.code,
953        Diagnostics.The_left_hand_side_of_a_for_of_statement_may_not_be_async.code,
954        Diagnostics.The_variable_declaration_of_a_for_in_statement_cannot_have_an_initializer.code,
955        Diagnostics.The_variable_declaration_of_a_for_of_statement_cannot_have_an_initializer.code,
956        Diagnostics.Trailing_comma_not_allowed.code,
957        Diagnostics.Variable_declaration_list_cannot_be_empty.code,
958        Diagnostics._0_and_1_operations_cannot_be_mixed_without_parentheses.code,
959        Diagnostics._0_expected.code,
960        Diagnostics._0_is_not_a_valid_meta_property_for_keyword_1_Did_you_mean_2.code,
961        Diagnostics._0_list_cannot_be_empty.code,
962        Diagnostics._0_modifier_already_seen.code,
963        Diagnostics._0_modifier_cannot_appear_on_a_constructor_declaration.code,
964        Diagnostics._0_modifier_cannot_appear_on_a_module_or_namespace_element.code,
965        Diagnostics._0_modifier_cannot_appear_on_a_parameter.code,
966        Diagnostics._0_modifier_cannot_appear_on_class_elements_of_this_kind.code,
967        Diagnostics._0_modifier_cannot_be_used_here.code,
968        Diagnostics._0_modifier_must_precede_1_modifier.code,
969        Diagnostics.const_declarations_can_only_be_declared_inside_a_block.code,
970        Diagnostics.const_declarations_must_be_initialized.code,
971        Diagnostics.extends_clause_already_seen.code,
972        Diagnostics.let_declarations_can_only_be_declared_inside_a_block.code,
973        Diagnostics.let_is_not_allowed_to_be_used_as_a_name_in_let_or_const_declarations.code,
974        Diagnostics.Class_constructor_may_not_be_a_generator.code,
975        Diagnostics.Class_constructor_may_not_be_an_accessor.code,
976        Diagnostics.await_expressions_are_only_allowed_within_async_functions_and_at_the_top_levels_of_modules.code,
977    ]);
978
979    /**
980     * Determine if source file needs to be re-created even if its text hasn't changed
981     */
982    function shouldProgramCreateNewSourceFiles(program: Program | undefined, newOptions: CompilerOptions): boolean {
983        if (!program) return false;
984        // If any compiler options change, we can't reuse old source file even if version match
985        // The change in options like these could result in change in syntax tree or `sourceFile.bindDiagnostics`.
986        return optionsHaveChanges(program.getCompilerOptions(), newOptions, sourceFileAffectingCompilerOptions);
987    }
988
989    function createCreateProgramOptions(rootNames: readonly string[], options: CompilerOptions, host?: CompilerHost, oldProgram?: Program, configFileParsingDiagnostics?: readonly Diagnostic[]): CreateProgramOptions {
990        return {
991            rootNames,
992            options,
993            host,
994            oldProgram,
995            configFileParsingDiagnostics
996        };
997    }
998
999    /**
1000     * Create a new 'Program' instance. A Program is an immutable collection of 'SourceFile's and a 'CompilerOptions'
1001     * that represent a compilation unit.
1002     *
1003     * Creating a program proceeds from a set of root files, expanding the set of inputs by following imports and
1004     * triple-slash-reference-path directives transitively. '@types' and triple-slash-reference-types are also pulled in.
1005     *
1006     * @param createProgramOptions - The options for creating a program.
1007     * @returns A 'Program' object.
1008     */
1009    export function createProgram(createProgramOptions: CreateProgramOptions): Program;
1010    /**
1011     * Create a new 'Program' instance. A Program is an immutable collection of 'SourceFile's and a 'CompilerOptions'
1012     * that represent a compilation unit.
1013     *
1014     * Creating a program proceeds from a set of root files, expanding the set of inputs by following imports and
1015     * triple-slash-reference-path directives transitively. '@types' and triple-slash-reference-types are also pulled in.
1016     *
1017     * @param rootNames - A set of root files.
1018     * @param options - The compiler options which should be used.
1019     * @param host - The host interacts with the underlying file system.
1020     * @param oldProgram - Reuses an old program structure.
1021     * @param configFileParsingDiagnostics - error during config file parsing
1022     * @returns A 'Program' object.
1023     */
1024    export function createProgram(rootNames: readonly string[], options: CompilerOptions, host?: CompilerHost, oldProgram?: Program, configFileParsingDiagnostics?: readonly Diagnostic[]): Program;
1025    export function createProgram(rootNamesOrOptions: readonly string[] | CreateProgramOptions, _options?: CompilerOptions, _host?: CompilerHost, _oldProgram?: Program, _configFileParsingDiagnostics?: readonly Diagnostic[]): Program {
1026        const createProgramOptions = isArray(rootNamesOrOptions) ? createCreateProgramOptions(rootNamesOrOptions, _options!, _host, _oldProgram, _configFileParsingDiagnostics) : rootNamesOrOptions; // TODO: GH#18217
1027        const { rootNames, options, configFileParsingDiagnostics, projectReferences } = createProgramOptions;
1028        let { oldProgram } = createProgramOptions;
1029
1030        let processingDefaultLibFiles: SourceFile[] | undefined;
1031        let processingOtherFiles: SourceFile[] | undefined;
1032        let files: SourceFile[];
1033        let symlinks: SymlinkCache | undefined;
1034        let commonSourceDirectory: string;
1035        let typeChecker: TypeChecker;
1036        let classifiableNames: Set<__String>;
1037        const ambientModuleNameToUnmodifiedFileName = new Map<string, string>();
1038        let fileReasons = createMultiMap<Path, FileIncludeReason>();
1039        const cachedBindAndCheckDiagnosticsForFile: DiagnosticCache<Diagnostic> = {};
1040        const cachedDeclarationDiagnosticsForFile: DiagnosticCache<DiagnosticWithLocation> = {};
1041
1042        let resolvedTypeReferenceDirectives = createModeAwareCache<ResolvedTypeReferenceDirective | undefined>();
1043        let fileProcessingDiagnostics: FilePreprocessingDiagnostics[] | undefined;
1044
1045        // The below settings are to track if a .js file should be add to the program if loaded via searching under node_modules or oh_modules.
1046        // This works as imported modules are discovered recursively in a depth first manner, specifically:
1047        // - For each root file, findSourceFile is called.
1048        // - This calls processImportedModules for each module imported in the source file.
1049        // - This calls resolveModuleNames, and then calls findSourceFile for each resolved module.
1050        // As all these operations happen - and are nested - within the createProgram call, they close over the below variables.
1051        // The current resolution depth is tracked by incrementing/decrementing as the depth first search progresses.
1052        const maxNodeModuleJsDepth = typeof options.maxNodeModuleJsDepth === "number" ? options.maxNodeModuleJsDepth : 0;
1053        let currentNodeModulesDepth = 0;
1054
1055        // If a module has some of its imports skipped due to being at the depth limit under node_modules or oh_modules, then track
1056        // this, as it may be imported at a shallower depth later, and then it will need its skipped imports processed.
1057        const modulesWithElidedImports = new Map<string, boolean>();
1058
1059        // Track source files that are source files found by searching under node_modules or oh_modules, as these shouldn't be compiled.
1060        const sourceFilesFoundSearchingNodeModules = new Map<string, boolean>();
1061
1062        tracing?.push(tracing.Phase.Program, "createProgram", { configFilePath: options.configFilePath, rootDir: options.rootDir }, /*separateBeginAndEnd*/ true);
1063        performance.mark("beforeProgram");
1064
1065        const host = createProgramOptions.host || createCompilerHost(options);
1066        const configParsingHost = parseConfigHostFromCompilerHostLike(host);
1067
1068        let skipDefaultLib = options.noLib;
1069        const getDefaultLibraryFileName = memoize(() => host.getDefaultLibFileName(options));
1070        const defaultLibraryPath = host.getDefaultLibLocation ? host.getDefaultLibLocation() : getDirectoryPath(getDefaultLibraryFileName());
1071        const programDiagnostics = createDiagnosticCollection();
1072        const currentDirectory = host.getCurrentDirectory();
1073        const supportedExtensions = getSupportedExtensions(options);
1074        const supportedExtensionsWithJsonIfResolveJsonModule = getSupportedExtensionsWithJsonIfResolveJsonModule(options, supportedExtensions);
1075
1076        // Map storing if there is emit blocking diagnostics for given input
1077        const hasEmitBlockingDiagnostics = new Map<string, boolean>();
1078        let _compilerOptionsObjectLiteralSyntax: ObjectLiteralExpression | false | undefined;
1079
1080        let moduleResolutionCache: ModuleResolutionCache | undefined;
1081        let typeReferenceDirectiveResolutionCache: TypeReferenceDirectiveResolutionCache | undefined;
1082        let actualResolveModuleNamesWorker: (moduleNames: string[], containingFile: SourceFile, containingFileName: string, reusedNames?: string[], redirectedReference?: ResolvedProjectReference) => ResolvedModuleFull[];
1083        const hasInvalidatedResolutions = host.hasInvalidatedResolutions || returnFalse;
1084        if (host.resolveModuleNames) {
1085            actualResolveModuleNamesWorker = (moduleNames, containingFile, containingFileName, reusedNames, redirectedReference) => host.resolveModuleNames!(Debug.checkEachDefined(moduleNames), containingFileName, reusedNames, redirectedReference, options, containingFile).map(resolved => {
1086                // An older host may have omitted extension, in which case we should infer it from the file extension of resolvedFileName.
1087                if (!resolved || (resolved as ResolvedModuleFull).extension !== undefined) {
1088                    return resolved as ResolvedModuleFull;
1089                }
1090                const withExtension = clone(resolved) as ResolvedModuleFull;
1091                withExtension.extension = extensionFromPath(resolved.resolvedFileName);
1092                return withExtension;
1093            });
1094            moduleResolutionCache = host.getModuleResolutionCache?.();
1095        }
1096        else {
1097            moduleResolutionCache = createModuleResolutionCache(currentDirectory, getCanonicalFileName, options);
1098            const loader = (moduleName: string, resolverMode: ModuleKind.CommonJS | ModuleKind.ESNext | undefined, containingFileName: string, redirectedReference: ResolvedProjectReference | undefined) => resolveModuleName(moduleName, containingFileName, options, host, moduleResolutionCache, redirectedReference, resolverMode).resolvedModule!; // TODO: GH#18217
1099            actualResolveModuleNamesWorker = (moduleNames, containingFile, containingFileName, _reusedNames, redirectedReference) => loadWithModeAwareCache<ResolvedModuleFull>(Debug.checkEachDefined(moduleNames), containingFile, containingFileName, redirectedReference, loader);
1100        }
1101
1102        let actualResolveTypeReferenceDirectiveNamesWorker: (typeDirectiveNames: string[] | readonly FileReference[], containingFile: string, redirectedReference?: ResolvedProjectReference, containingFileMode?: SourceFile["impliedNodeFormat"] | undefined) => (ResolvedTypeReferenceDirective | undefined)[];
1103        if (host.resolveTypeReferenceDirectives) {
1104            actualResolveTypeReferenceDirectiveNamesWorker = (typeDirectiveNames, containingFile, redirectedReference, containingFileMode) => host.resolveTypeReferenceDirectives!(Debug.checkEachDefined(typeDirectiveNames), containingFile, redirectedReference, options, containingFileMode);
1105        }
1106        else {
1107            typeReferenceDirectiveResolutionCache = createTypeReferenceDirectiveResolutionCache(currentDirectory, getCanonicalFileName, /*options*/ undefined, moduleResolutionCache?.getPackageJsonInfoCache());
1108            const loader = (typesRef: string, containingFile: string, redirectedReference: ResolvedProjectReference | undefined, resolutionMode: SourceFile["impliedNodeFormat"] | undefined) => resolveTypeReferenceDirective(
1109                typesRef,
1110                containingFile,
1111                options,
1112                host,
1113                redirectedReference,
1114                typeReferenceDirectiveResolutionCache,
1115                resolutionMode,
1116            ).resolvedTypeReferenceDirective!; // TODO: GH#18217
1117            actualResolveTypeReferenceDirectiveNamesWorker = (typeReferenceDirectiveNames, containingFile, redirectedReference, containingFileMode) => loadWithTypeDirectiveCache<ResolvedTypeReferenceDirective>(Debug.checkEachDefined(typeReferenceDirectiveNames), containingFile, redirectedReference, containingFileMode, loader);
1118        }
1119
1120        // Map from a stringified PackageId to the source file with that id.
1121        // Only one source file may have a given packageId. Others become redirects (see createRedirectSourceFile).
1122        // `packageIdToSourceFile` is only used while building the program, while `sourceFileToPackageName` and `isSourceFileTargetOfRedirect` are kept around.
1123        const packageIdToSourceFile = new Map<string, SourceFile>();
1124        // Maps from a SourceFile's `.path` to the name of the package it was imported with.
1125        let sourceFileToPackageName = new Map<Path, string>();
1126        // Key is a file name. Value is the (non-empty, or undefined) list of files that redirect to it.
1127        let redirectTargetsMap = createMultiMap<Path, string>();
1128        let usesUriStyleNodeCoreModules = false;
1129
1130        /**
1131         * map with
1132         * - SourceFile if present
1133         * - false if sourceFile missing for source of project reference redirect
1134         * - undefined otherwise
1135         */
1136        const filesByName = new Map<string, SourceFile | false | undefined>();
1137        let missingFilePaths: readonly Path[] | undefined;
1138        // stores 'filename -> file association' ignoring case
1139        // used to track cases when two file names differ only in casing
1140        const filesByNameIgnoreCase = host.useCaseSensitiveFileNames() ? new Map<string, SourceFile>() : undefined;
1141
1142        // A parallel array to projectReferences storing the results of reading in the referenced tsconfig files
1143        let resolvedProjectReferences: readonly (ResolvedProjectReference | undefined)[] | undefined;
1144        let projectReferenceRedirects: ESMap<Path, ResolvedProjectReference | false> | undefined;
1145        let mapFromFileToProjectReferenceRedirects: ESMap<Path, Path> | undefined;
1146        let mapFromToProjectReferenceRedirectSource: ESMap<Path, SourceOfProjectReferenceRedirect> | undefined;
1147
1148        const useSourceOfProjectReferenceRedirect = !!host.useSourceOfProjectReferenceRedirect?.() &&
1149            !options.disableSourceOfProjectReferenceRedirect;
1150        const { onProgramCreateComplete, fileExists, directoryExists } = updateHostForUseSourceOfProjectReferenceRedirect({
1151            compilerHost: host,
1152            getSymlinkCache,
1153            useSourceOfProjectReferenceRedirect,
1154            toPath,
1155            getResolvedProjectReferences,
1156            getSourceOfProjectReferenceRedirect,
1157            forEachResolvedProjectReference,
1158            options: _options
1159        });
1160        const readFile = host.readFile.bind(host) as typeof host.readFile;
1161
1162        tracing?.push(tracing.Phase.Program, "shouldProgramCreateNewSourceFiles", { hasOldProgram: !!oldProgram });
1163        const shouldCreateNewSourceFile = shouldProgramCreateNewSourceFiles(oldProgram, options);
1164        tracing?.pop();
1165        // We set `structuralIsReused` to `undefined` because `tryReuseStructureFromOldProgram` calls `tryReuseStructureFromOldProgram` which checks
1166        // `structuralIsReused`, which would be a TDZ violation if it was not set in advance to `undefined`.
1167        let structureIsReused: StructureIsReused;
1168        tracing?.push(tracing.Phase.Program, "tryReuseStructureFromOldProgram", {});
1169        structureIsReused = tryReuseStructureFromOldProgram(); // eslint-disable-line prefer-const
1170        tracing?.pop();
1171        if (structureIsReused !== StructureIsReused.Completely) {
1172            processingDefaultLibFiles = [];
1173            processingOtherFiles = [];
1174
1175            if (projectReferences) {
1176                if (!resolvedProjectReferences) {
1177                    resolvedProjectReferences = projectReferences.map(parseProjectReferenceConfigFile);
1178                }
1179                if (rootNames.length) {
1180                    resolvedProjectReferences?.forEach((parsedRef, index) => {
1181                        if (!parsedRef) return;
1182                        const out = outFile(parsedRef.commandLine.options);
1183                        if (useSourceOfProjectReferenceRedirect) {
1184                            if (out || getEmitModuleKind(parsedRef.commandLine.options) === ModuleKind.None) {
1185                                for (const fileName of parsedRef.commandLine.fileNames) {
1186                                    processProjectReferenceFile(fileName, { kind: FileIncludeKind.SourceFromProjectReference, index });
1187                                }
1188                            }
1189                        }
1190                        else {
1191                            if (out) {
1192                                processProjectReferenceFile(changeExtension(out, ".d.ts"), { kind: FileIncludeKind.OutputFromProjectReference, index });
1193                            }
1194                            else if (getEmitModuleKind(parsedRef.commandLine.options) === ModuleKind.None) {
1195                                const getCommonSourceDirectory = memoize(() => getCommonSourceDirectoryOfConfig(parsedRef.commandLine, !host.useCaseSensitiveFileNames()));
1196                                for (const fileName of parsedRef.commandLine.fileNames) {
1197                                    if (!isDeclarationFileName(fileName) && !fileExtensionIs(fileName, Extension.Json)) {
1198                                        processProjectReferenceFile(getOutputDeclarationFileName(fileName, parsedRef.commandLine, !host.useCaseSensitiveFileNames(), getCommonSourceDirectory), { kind: FileIncludeKind.OutputFromProjectReference, index });
1199                                    }
1200                                }
1201                            }
1202                        }
1203                    });
1204                }
1205            }
1206
1207            tracing?.push(tracing.Phase.Program, "processRootFiles", { count: rootNames.length });
1208            forEach(rootNames, (name, index) => processRootFile(name, /*isDefaultLib*/ false, /*ignoreNoDefaultLib*/ false, { kind: FileIncludeKind.RootFile, index }));
1209            tracing?.pop();
1210
1211            // load type declarations specified via 'types' argument or implicitly from types/ and node_modules/@types folders
1212            const typeReferences: string[] = rootNames.length ? getAutomaticTypeDirectiveNames(options, host) : emptyArray;
1213
1214            if (typeReferences.length) {
1215                tracing?.push(tracing.Phase.Program, "processTypeReferences", { count: typeReferences.length });
1216                // This containingFilename needs to match with the one used in managed-side
1217                const containingDirectory = options.configFilePath ? getDirectoryPath(options.configFilePath) : host.getCurrentDirectory();
1218                const containingFilename = combinePaths(containingDirectory, inferredTypesContainingFile);
1219                const resolutions = resolveTypeReferenceDirectiveNamesWorker(typeReferences, containingFilename);
1220                for (let i = 0; i < typeReferences.length; i++) {
1221                    // under node16/nodenext module resolution, load `types`/ata include names as cjs resolution results by passing an `undefined` mode
1222                    processTypeReferenceDirective(typeReferences[i], /*mode*/ undefined, resolutions[i], { kind: FileIncludeKind.AutomaticTypeDirectiveFile, typeReference: typeReferences[i], packageId: resolutions[i]?.packageId });
1223                }
1224                tracing?.pop();
1225            }
1226
1227            // Do not process the default library if:
1228            //  - The '--noLib' flag is used.
1229            //  - A 'no-default-lib' reference comment is encountered in
1230            //      processing the root files.
1231            if (rootNames.length && !skipDefaultLib) {
1232                // If '--lib' is not specified, include default library file according to '--target'
1233                // otherwise, using options specified in '--lib' instead of '--target' default library file
1234                const defaultLibraryFileName = getDefaultLibraryFileName();
1235                if (!options.lib && defaultLibraryFileName) {
1236                    processRootFile(defaultLibraryFileName, /*isDefaultLib*/ true, /*ignoreNoDefaultLib*/ false, { kind: FileIncludeKind.LibFile });
1237                }
1238                else {
1239                    forEach(options.lib, (libFileName, index) => {
1240                        processRootFile(pathForLibFile(libFileName), /*isDefaultLib*/ true, /*ignoreNoDefaultLib*/ false, { kind: FileIncludeKind.LibFile, index });
1241                    });
1242
1243                    const etsComponentsLib = options.ets?.libs ?? [];
1244                    if (etsComponentsLib.length) {
1245                        forEach(etsComponentsLib, libFileName => {
1246                            processRootFile(combinePaths(libFileName), /*isDefaultLib*/ true, /*ignoreNoDefaultLib*/ false, { kind: FileIncludeKind.LibFile });
1247                        });
1248                    }
1249                }
1250            }
1251
1252            missingFilePaths = arrayFrom(mapDefinedIterator(filesByName.entries(), ([path, file]) => file === undefined ? path as Path : undefined));
1253            files = stableSort(processingDefaultLibFiles, compareDefaultLibFiles).concat(processingOtherFiles);
1254            processingDefaultLibFiles = undefined;
1255            processingOtherFiles = undefined;
1256        }
1257
1258        Debug.assert(!!missingFilePaths);
1259
1260        // Release any files we have acquired in the old program but are
1261        // not part of the new program.
1262        if (oldProgram && host.onReleaseOldSourceFile) {
1263            const oldSourceFiles = oldProgram.getSourceFiles();
1264            for (const oldSourceFile of oldSourceFiles) {
1265                const newFile = getSourceFileByPath(oldSourceFile.resolvedPath);
1266                if (shouldCreateNewSourceFile || !newFile || newFile.impliedNodeFormat !== oldSourceFile.impliedNodeFormat ||
1267                    // old file wasn't redirect but new file is
1268                    (oldSourceFile.resolvedPath === oldSourceFile.path && newFile.resolvedPath !== oldSourceFile.path)) {
1269                    host.onReleaseOldSourceFile(oldSourceFile, oldProgram.getCompilerOptions(), !!getSourceFileByPath(oldSourceFile.path));
1270                }
1271            }
1272            if (!host.getParsedCommandLine) {
1273                oldProgram.forEachResolvedProjectReference(resolvedProjectReference => {
1274                    if (!getResolvedProjectReferenceByPath(resolvedProjectReference.sourceFile.path)) {
1275                        host.onReleaseOldSourceFile!(resolvedProjectReference.sourceFile, oldProgram!.getCompilerOptions(), /*hasSourceFileByPath*/ false);
1276                    }
1277                });
1278            }
1279        }
1280
1281        // Release commandlines that new program does not use
1282        if (oldProgram && host.onReleaseParsedCommandLine) {
1283            forEachProjectReference(
1284                oldProgram.getProjectReferences(),
1285                oldProgram.getResolvedProjectReferences(),
1286                (oldResolvedRef, parent, index) => {
1287                    const oldReference = parent?.commandLine.projectReferences![index] || oldProgram!.getProjectReferences()![index];
1288                    const oldRefPath = resolveProjectReferencePath(oldReference);
1289                    if (!projectReferenceRedirects?.has(toPath(oldRefPath))) {
1290                        host.onReleaseParsedCommandLine!(oldRefPath, oldResolvedRef, oldProgram!.getCompilerOptions());
1291                    }
1292                }
1293            );
1294        }
1295
1296        typeReferenceDirectiveResolutionCache = undefined;
1297
1298        // unconditionally set oldProgram to undefined to prevent it from being captured in closure
1299        oldProgram = undefined;
1300
1301        const program: Program = {
1302            getRootFileNames: () => rootNames,
1303            getSourceFile,
1304            getSourceFileByPath,
1305            getSourceFiles: () => files,
1306            getMissingFilePaths: () => missingFilePaths!, // TODO: GH#18217
1307            getModuleResolutionCache: () => moduleResolutionCache,
1308            getFilesByNameMap: () => filesByName,
1309            getCompilerOptions: () => options,
1310            getSyntacticDiagnostics,
1311            getOptionsDiagnostics,
1312            getGlobalDiagnostics,
1313            getSemanticDiagnostics,
1314            getCachedSemanticDiagnostics,
1315            getSuggestionDiagnostics,
1316            getDeclarationDiagnostics,
1317            getBindAndCheckDiagnostics,
1318            getProgramDiagnostics,
1319            getTypeChecker,
1320            getEtsLibSFromProgram,
1321            getClassifiableNames,
1322            getCommonSourceDirectory,
1323            emit,
1324            getCurrentDirectory: () => currentDirectory,
1325            getNodeCount: () => getTypeChecker().getNodeCount(),
1326            getIdentifierCount: () => getTypeChecker().getIdentifierCount(),
1327            getSymbolCount: () => getTypeChecker().getSymbolCount(),
1328            getTypeCount: () => getTypeChecker().getTypeCount(),
1329            getInstantiationCount: () => getTypeChecker().getInstantiationCount(),
1330            getRelationCacheSizes: () => getTypeChecker().getRelationCacheSizes(),
1331            getFileProcessingDiagnostics: () => fileProcessingDiagnostics,
1332            getResolvedTypeReferenceDirectives: () => resolvedTypeReferenceDirectives,
1333            isSourceFileFromExternalLibrary,
1334            isSourceFileDefaultLibrary,
1335            getSourceFileFromReference,
1336            getLibFileFromReference,
1337            sourceFileToPackageName,
1338            redirectTargetsMap,
1339            usesUriStyleNodeCoreModules,
1340            isEmittedFile,
1341            getConfigFileParsingDiagnostics,
1342            getResolvedModuleWithFailedLookupLocationsFromCache,
1343            getProjectReferences,
1344            getResolvedProjectReferences,
1345            getProjectReferenceRedirect,
1346            getResolvedProjectReferenceToRedirect,
1347            getResolvedProjectReferenceByPath,
1348            forEachResolvedProjectReference,
1349            isSourceOfProjectReferenceRedirect,
1350            emitBuildInfo,
1351            fileExists,
1352            readFile,
1353            directoryExists,
1354            getSymlinkCache,
1355            realpath: host.realpath?.bind(host),
1356            useCaseSensitiveFileNames: () => host.useCaseSensitiveFileNames(),
1357            getFileIncludeReasons: () => fileReasons,
1358            structureIsReused,
1359            writeFile,
1360            getJsDocNodeCheckedConfig: host.getJsDocNodeCheckedConfig,
1361            getJsDocNodeConditionCheckedResult: host. getJsDocNodeConditionCheckedResult,
1362            getFileCheckedModuleInfo: host.getFileCheckedModuleInfo,
1363        };
1364
1365        onProgramCreateComplete();
1366
1367        // Add file processingDiagnostics
1368        fileProcessingDiagnostics?.forEach(diagnostic => {
1369            switch (diagnostic.kind) {
1370                case FilePreprocessingDiagnosticsKind.FilePreprocessingFileExplainingDiagnostic:
1371                    return programDiagnostics.add(createDiagnosticExplainingFile(diagnostic.file && getSourceFileByPath(diagnostic.file), diagnostic.fileProcessingReason, diagnostic.diagnostic, diagnostic.args || emptyArray));
1372                case FilePreprocessingDiagnosticsKind.FilePreprocessingReferencedDiagnostic:
1373                    const { file, pos, end } = getReferencedFileLocation(getSourceFileByPath, diagnostic.reason) as ReferenceFileLocation;
1374                    return programDiagnostics.add(createFileDiagnostic(file, Debug.checkDefined(pos), Debug.checkDefined(end) - pos, diagnostic.diagnostic, ...diagnostic.args || emptyArray));
1375                default:
1376                    Debug.assertNever(diagnostic);
1377            }
1378        });
1379
1380        verifyCompilerOptions();
1381        performance.mark("afterProgram");
1382        performance.measure("Program", "beforeProgram", "afterProgram");
1383        tracing?.pop();
1384
1385        return program;
1386
1387        function addResolutionDiagnostics(list: Diagnostic[] | undefined) {
1388            if (!list) return;
1389            for (const elem of list) {
1390                programDiagnostics.add(elem);
1391            }
1392        }
1393
1394        function pullDiagnosticsFromCache(names: string[] | readonly FileReference[], containingFile: SourceFile) {
1395            if (!moduleResolutionCache) return;
1396            const containingFileName = getNormalizedAbsolutePath(containingFile.originalFileName, currentDirectory);
1397            const containingFileMode = !isString(containingFile) ? containingFile.impliedNodeFormat : undefined;
1398            const containingDir = getDirectoryPath(containingFileName);
1399            const redirectedReference = getRedirectReferenceForResolution(containingFile);
1400            let i = 0;
1401            for (const n of names) {
1402                // mimics logic done in the resolution cache, should be resilient to upgrading it to use `FileReference`s for non-type-reference modal lookups to make it rely on the index in the list less
1403                const mode = typeof n === "string" ? getModeForResolutionAtIndex(containingFile, i) : getModeForFileReference(n, containingFileMode);
1404                const name = typeof n === "string" ? n : n.fileName;
1405                i++;
1406                // only nonrelative names hit the cache, and, at least as of right now, only nonrelative names can issue diagnostics
1407                // (Since diagnostics are only issued via import or export map lookup)
1408                // This may totally change if/when the issue of output paths not mapping to input files is fixed in a broader context
1409                // When it is, how we extract diagnostics from the module name resolver will have the be refined - the current cache
1410                // APIs wrapping the underlying resolver make it almost impossible to smuggle the diagnostics out in a generalized way
1411                if (isExternalModuleNameRelative(name)) continue;
1412                const diags = moduleResolutionCache.getOrCreateCacheForModuleName(name, mode, redirectedReference).get(containingDir)?.resolutionDiagnostics;
1413                addResolutionDiagnostics(diags);
1414            }
1415        }
1416
1417        function resolveModuleNamesWorker(moduleNames: string[], containingFile: SourceFile, reusedNames: string[] | undefined): readonly ResolvedModuleFull[] {
1418            if (!moduleNames.length) return emptyArray;
1419            const containingFileName = getNormalizedAbsolutePath(containingFile.originalFileName, currentDirectory);
1420            const redirectedReference = getRedirectReferenceForResolution(containingFile);
1421            tracing?.push(tracing.Phase.Program, "resolveModuleNamesWorker", { containingFileName });
1422            performance.mark("beforeResolveModule");
1423            const result = actualResolveModuleNamesWorker(moduleNames, containingFile, containingFileName, reusedNames, redirectedReference);
1424            performance.mark("afterResolveModule");
1425            performance.measure("ResolveModule", "beforeResolveModule", "afterResolveModule");
1426            tracing?.pop();
1427            pullDiagnosticsFromCache(moduleNames, containingFile);
1428            return result;
1429        }
1430
1431        function resolveTypeReferenceDirectiveNamesWorker(typeDirectiveNames: string[] | readonly FileReference[], containingFile: string | SourceFile): readonly (ResolvedTypeReferenceDirective | undefined)[] {
1432            if (!typeDirectiveNames.length) return [];
1433            const containingFileName = !isString(containingFile) ? getNormalizedAbsolutePath(containingFile.originalFileName, currentDirectory) : containingFile;
1434            const redirectedReference = !isString(containingFile) ? getRedirectReferenceForResolution(containingFile) : undefined;
1435            const containingFileMode = !isString(containingFile) ? containingFile.impliedNodeFormat : undefined;
1436            tracing?.push(tracing.Phase.Program, "resolveTypeReferenceDirectiveNamesWorker", { containingFileName });
1437            performance.mark("beforeResolveTypeReference");
1438            const result = actualResolveTypeReferenceDirectiveNamesWorker(typeDirectiveNames, containingFileName, redirectedReference, containingFileMode);
1439            performance.mark("afterResolveTypeReference");
1440            performance.measure("ResolveTypeReference", "beforeResolveTypeReference", "afterResolveTypeReference");
1441            tracing?.pop();
1442            return result;
1443        }
1444
1445        function getRedirectReferenceForResolution(file: SourceFile) {
1446            const redirect = getResolvedProjectReferenceToRedirect(file.originalFileName);
1447            if (redirect || !isDeclarationFileName(file.originalFileName)) return redirect;
1448
1449            // The originalFileName could not be actual source file name if file found was d.ts from referecned project
1450            // So in this case try to look up if this is output from referenced project, if it is use the redirected project in that case
1451            const resultFromDts = getRedirectReferenceForResolutionFromSourceOfProject(file.path);
1452            if (resultFromDts) return resultFromDts;
1453
1454            // If preserveSymlinks is true, module resolution wont jump the symlink
1455            // but the resolved real path may be the .d.ts from project reference
1456            // Note:: Currently we try the real path only if the
1457            // file is from node_modules to avoid having to run real path on all file paths
1458            if (!host.realpath || !options.preserveSymlinks || (!stringContains(file.originalFileName, nodeModulesPathPart) && !stringContains(file.originalFileName, ohModulesPathPart))) return undefined;
1459            const realDeclarationPath = toPath(host.realpath(file.originalFileName));
1460            return realDeclarationPath === file.path ? undefined : getRedirectReferenceForResolutionFromSourceOfProject(realDeclarationPath);
1461        }
1462
1463        function getRedirectReferenceForResolutionFromSourceOfProject(filePath: Path) {
1464            const source = getSourceOfProjectReferenceRedirect(filePath);
1465            if (isString(source)) return getResolvedProjectReferenceToRedirect(source);
1466            if (!source) return undefined;
1467            // Output of .d.ts file so return resolved ref that matches the out file name
1468            return forEachResolvedProjectReference(resolvedRef => {
1469                const out = outFile(resolvedRef.commandLine.options);
1470                if (!out) return undefined;
1471                return toPath(out) === filePath ? resolvedRef : undefined;
1472            });
1473        }
1474
1475        function compareDefaultLibFiles(a: SourceFile, b: SourceFile) {
1476            return compareValues(getDefaultLibFilePriority(a), getDefaultLibFilePriority(b));
1477        }
1478
1479        function getDefaultLibFilePriority(a: SourceFile) {
1480            if (containsPath(defaultLibraryPath, a.fileName, /*ignoreCase*/ false)) {
1481                const basename = getBaseFileName(a.fileName);
1482                if (basename === "lib.d.ts" || basename === "lib.es6.d.ts") return 0;
1483                const name = removeSuffix(removePrefix(basename, "lib."), ".d.ts");
1484                const index = libs.indexOf(name);
1485                if (index !== -1) return index + 1;
1486            }
1487            return libs.length + 2;
1488        }
1489
1490        function getResolvedModuleWithFailedLookupLocationsFromCache(moduleName: string, containingFile: string, mode?: ModuleKind.CommonJS | ModuleKind.ESNext): ResolvedModuleWithFailedLookupLocations | undefined {
1491            return moduleResolutionCache && resolveModuleNameFromCache(moduleName, containingFile, moduleResolutionCache, mode);
1492        }
1493
1494        function toPath(fileName: string): Path {
1495            return ts.toPath(fileName, currentDirectory, getCanonicalFileName);
1496        }
1497
1498        function getCommonSourceDirectory() {
1499            if (commonSourceDirectory === undefined) {
1500                const emittedFiles = filter(files, file => sourceFileMayBeEmitted(file, program));
1501                commonSourceDirectory = ts.getCommonSourceDirectory(
1502                    options,
1503                    () => mapDefined(emittedFiles, file => file.isDeclarationFile ? undefined : file.fileName),
1504                    currentDirectory,
1505                    getCanonicalFileName,
1506                    commonSourceDirectory => checkSourceFilesBelongToPath(emittedFiles, commonSourceDirectory)
1507                );
1508            }
1509            return commonSourceDirectory;
1510        }
1511
1512        function getClassifiableNames() {
1513            if (!classifiableNames) {
1514                // Initialize a checker so that all our files are bound.
1515                getTypeChecker();
1516                classifiableNames = new Set();
1517
1518                for (const sourceFile of files) {
1519                    sourceFile.classifiableNames?.forEach(value => classifiableNames.add(value));
1520                }
1521            }
1522
1523            return classifiableNames;
1524        }
1525
1526        function resolveModuleNamesReusingOldState(moduleNames: string[], file: SourceFile): readonly (ResolvedModuleFull | undefined)[] {
1527            if (structureIsReused === StructureIsReused.Not && !file.ambientModuleNames.length) {
1528                // If the old program state does not permit reusing resolutions and `file` does not contain locally defined ambient modules,
1529                // the best we can do is fallback to the default logic.
1530                return resolveModuleNamesWorker(moduleNames, file, /*reusedNames*/ undefined);
1531            }
1532
1533            const oldSourceFile = oldProgram && oldProgram.getSourceFile(file.fileName);
1534            if (oldSourceFile !== file && file.resolvedModules) {
1535                // `file` was created for the new program.
1536                //
1537                // We only set `file.resolvedModules` via work from the current function,
1538                // so it is defined iff we already called the current function on `file`.
1539                // That call happened no later than the creation of the `file` object,
1540                // which per above occurred during the current program creation.
1541                // Since we assume the filesystem does not change during program creation,
1542                // it is safe to reuse resolutions from the earlier call.
1543                const result: (ResolvedModuleFull | undefined)[] = [];
1544                let i = 0;
1545                for (const moduleName of moduleNames) {
1546                    const resolvedModule = file.resolvedModules.get(moduleName, getModeForResolutionAtIndex(file, i));
1547                    i++;
1548                    result.push(resolvedModule);
1549                }
1550                return result;
1551            }
1552            // At this point, we know at least one of the following hold:
1553            // - file has local declarations for ambient modules
1554            // - old program state is available
1555            // With this information, we can infer some module resolutions without performing resolution.
1556
1557            /** An ordered list of module names for which we cannot recover the resolution. */
1558            let unknownModuleNames: string[] | undefined;
1559            /**
1560             * The indexing of elements in this list matches that of `moduleNames`.
1561             *
1562             * Before combining results, result[i] is in one of the following states:
1563             * * undefined: needs to be recomputed,
1564             * * predictedToResolveToAmbientModuleMarker: known to be an ambient module.
1565             * Needs to be reset to undefined before returning,
1566             * * ResolvedModuleFull instance: can be reused.
1567             */
1568            let result: (ResolvedModuleFull | undefined)[] | undefined;
1569            let reusedNames: string[] | undefined;
1570            /** A transient placeholder used to mark predicted resolution in the result list. */
1571            const predictedToResolveToAmbientModuleMarker: ResolvedModuleFull = {} as any;
1572
1573            for (let i = 0; i < moduleNames.length; i++) {
1574                const moduleName = moduleNames[i];
1575                // If the source file is unchanged and doesnt have invalidated resolution, reuse the module resolutions
1576                if (file === oldSourceFile && !hasInvalidatedResolutions(oldSourceFile.path)) {
1577                    const oldResolvedModule = getResolvedModule(oldSourceFile, moduleName, getModeForResolutionAtIndex(oldSourceFile, i));
1578                    if (oldResolvedModule) {
1579                        if (isTraceEnabled(options, host)) {
1580                            trace(host,
1581                                oldResolvedModule.packageId ?
1582                                    Diagnostics.Reusing_resolution_of_module_0_from_1_of_old_program_it_was_successfully_resolved_to_2_with_Package_ID_3 :
1583                                    Diagnostics.Reusing_resolution_of_module_0_from_1_of_old_program_it_was_successfully_resolved_to_2,
1584                                moduleName,
1585                                getNormalizedAbsolutePath(file.originalFileName, currentDirectory),
1586                                oldResolvedModule.resolvedFileName,
1587                                oldResolvedModule.packageId && packageIdToString(oldResolvedModule.packageId)
1588                            );
1589                        }
1590                        (result || (result = new Array(moduleNames.length)))[i] = oldResolvedModule;
1591                        (reusedNames || (reusedNames = [])).push(moduleName);
1592                        continue;
1593                    }
1594                }
1595                // We know moduleName resolves to an ambient module provided that moduleName:
1596                // - is in the list of ambient modules locally declared in the current source file.
1597                // - resolved to an ambient module in the old program whose declaration is in an unmodified file
1598                //   (so the same module declaration will land in the new program)
1599                let resolvesToAmbientModuleInNonModifiedFile = false;
1600                if (contains(file.ambientModuleNames, moduleName)) {
1601                    resolvesToAmbientModuleInNonModifiedFile = true;
1602                    if (isTraceEnabled(options, host)) {
1603                        trace(host, Diagnostics.Module_0_was_resolved_as_locally_declared_ambient_module_in_file_1, moduleName, getNormalizedAbsolutePath(file.originalFileName, currentDirectory));
1604                    }
1605                }
1606                else {
1607                    resolvesToAmbientModuleInNonModifiedFile = moduleNameResolvesToAmbientModuleInNonModifiedFile(moduleName, i);
1608                }
1609
1610                if (resolvesToAmbientModuleInNonModifiedFile) {
1611                    (result || (result = new Array(moduleNames.length)))[i] = predictedToResolveToAmbientModuleMarker;
1612                }
1613                else {
1614                    // Resolution failed in the old program, or resolved to an ambient module for which we can't reuse the result.
1615                    (unknownModuleNames || (unknownModuleNames = [])).push(moduleName);
1616                }
1617            }
1618
1619            const resolutions = unknownModuleNames && unknownModuleNames.length
1620                ? resolveModuleNamesWorker(unknownModuleNames, file, reusedNames)
1621                : emptyArray;
1622
1623            // Combine results of resolutions and predicted results
1624            if (!result) {
1625                // There were no unresolved/ambient resolutions.
1626                Debug.assert(resolutions.length === moduleNames.length);
1627                return resolutions;
1628            }
1629
1630            let j = 0;
1631            for (let i = 0; i < result.length; i++) {
1632                if (result[i]) {
1633                    // `result[i]` is either a `ResolvedModuleFull` or a marker.
1634                    // If it is the former, we can leave it as is.
1635                    if (result[i] === predictedToResolveToAmbientModuleMarker) {
1636                        result[i] = undefined;
1637                    }
1638                }
1639                else {
1640                    result[i] = resolutions[j];
1641                    j++;
1642                }
1643            }
1644            Debug.assert(j === resolutions.length);
1645
1646            return result;
1647
1648            // If we change our policy of rechecking failed lookups on each program create,
1649            // we should adjust the value returned here.
1650            function moduleNameResolvesToAmbientModuleInNonModifiedFile(moduleName: string, index: number): boolean {
1651                if (index >= length(oldSourceFile?.imports) + length(oldSourceFile?.moduleAugmentations)) return false; // mode index out of bounds, don't reuse resolution
1652                const resolutionToFile = getResolvedModule(oldSourceFile, moduleName, oldSourceFile && getModeForResolutionAtIndex(oldSourceFile, index));
1653                const resolvedFile = resolutionToFile && oldProgram!.getSourceFile(resolutionToFile.resolvedFileName);
1654                if (resolutionToFile && resolvedFile) {
1655                    // In the old program, we resolved to an ambient module that was in the same
1656                    //   place as we expected to find an actual module file.
1657                    // We actually need to return 'false' here even though this seems like a 'true' case
1658                    //   because the normal module resolution algorithm will find this anyway.
1659                    return false;
1660                }
1661
1662                // at least one of declarations should come from non-modified source file
1663                const unmodifiedFile = ambientModuleNameToUnmodifiedFileName.get(moduleName);
1664
1665                if (!unmodifiedFile) {
1666                    return false;
1667                }
1668
1669                if (isTraceEnabled(options, host)) {
1670                    trace(host, Diagnostics.Module_0_was_resolved_as_ambient_module_declared_in_1_since_this_file_was_not_modified, moduleName, unmodifiedFile);
1671                }
1672                return true;
1673            }
1674        }
1675
1676        function canReuseProjectReferences(): boolean {
1677            return !forEachProjectReference(
1678                oldProgram!.getProjectReferences(),
1679                oldProgram!.getResolvedProjectReferences(),
1680                (oldResolvedRef, parent, index) => {
1681                    const newRef = (parent ? parent.commandLine.projectReferences : projectReferences)![index];
1682                    const newResolvedRef = parseProjectReferenceConfigFile(newRef);
1683                    if (oldResolvedRef) {
1684                        // Resolved project reference has gone missing or changed
1685                        return !newResolvedRef ||
1686                            newResolvedRef.sourceFile !== oldResolvedRef.sourceFile ||
1687                            !arrayIsEqualTo(oldResolvedRef.commandLine.fileNames, newResolvedRef.commandLine.fileNames);
1688                    }
1689                    else {
1690                        // A previously-unresolved reference may be resolved now
1691                        return newResolvedRef !== undefined;
1692                    }
1693                },
1694                (oldProjectReferences, parent) => {
1695                    // If array of references is changed, we cant resue old program
1696                    const newReferences = parent ? getResolvedProjectReferenceByPath(parent.sourceFile.path)!.commandLine.projectReferences : projectReferences;
1697                    return !arrayIsEqualTo(oldProjectReferences, newReferences, projectReferenceIsEqualTo);
1698                }
1699            );
1700        }
1701
1702        function tryReuseStructureFromOldProgram(): StructureIsReused {
1703            if (!oldProgram) {
1704                return StructureIsReused.Not;
1705            }
1706
1707            // check properties that can affect structure of the program or module resolution strategy
1708            // if any of these properties has changed - structure cannot be reused
1709            const oldOptions = oldProgram.getCompilerOptions();
1710            if (changesAffectModuleResolution(oldOptions, options)) {
1711                return StructureIsReused.Not;
1712            }
1713
1714            // there is an old program, check if we can reuse its structure
1715            const oldRootNames = oldProgram.getRootFileNames();
1716            if (!arrayIsEqualTo(oldRootNames, rootNames)) {
1717                return StructureIsReused.Not;
1718            }
1719
1720            // Check if any referenced project tsconfig files are different
1721            if (!canReuseProjectReferences()) {
1722                return StructureIsReused.Not;
1723            }
1724            if (projectReferences) {
1725                resolvedProjectReferences = projectReferences.map(parseProjectReferenceConfigFile);
1726            }
1727
1728            // check if program source files has changed in the way that can affect structure of the program
1729            const newSourceFiles: SourceFile[] = [];
1730            const modifiedSourceFiles: { oldFile: SourceFile, newFile: SourceFile }[] = [];
1731            structureIsReused = StructureIsReused.Completely;
1732
1733            // If the missing file paths are now present, it can change the progam structure,
1734            // and hence cant reuse the structure.
1735            // This is same as how we dont reuse the structure if one of the file from old program is now missing
1736            if (oldProgram.getMissingFilePaths().some(missingFilePath => host.fileExists(missingFilePath))) {
1737                return StructureIsReused.Not;
1738            }
1739
1740            const oldSourceFiles = oldProgram.getSourceFiles();
1741            const enum SeenPackageName { Exists, Modified }
1742            const seenPackageNames = new Map<string, SeenPackageName>();
1743
1744            for (const oldSourceFile of oldSourceFiles) {
1745                const sourceFileOptions = getCreateSourceFileOptions(oldSourceFile.fileName, moduleResolutionCache, host, options);
1746                let newSourceFile = host.getSourceFileByPath
1747                    ? host.getSourceFileByPath(oldSourceFile.fileName, oldSourceFile.resolvedPath, sourceFileOptions, /*onError*/ undefined, shouldCreateNewSourceFile || sourceFileOptions.impliedNodeFormat !== oldSourceFile.impliedNodeFormat)
1748                    : host.getSourceFile(oldSourceFile.fileName, sourceFileOptions, /*onError*/ undefined, shouldCreateNewSourceFile || sourceFileOptions.impliedNodeFormat !== oldSourceFile.impliedNodeFormat); // TODO: GH#18217
1749
1750                if (!newSourceFile) {
1751                    return StructureIsReused.Not;
1752                }
1753                newSourceFile.packageJsonLocations = sourceFileOptions.packageJsonLocations?.length ? sourceFileOptions.packageJsonLocations : undefined;
1754                newSourceFile.packageJsonScope = sourceFileOptions.packageJsonScope;
1755
1756                Debug.assert(!newSourceFile.redirectInfo, "Host should not return a redirect source file from `getSourceFile`");
1757
1758                let fileChanged: boolean;
1759                if (oldSourceFile.redirectInfo) {
1760                    // We got `newSourceFile` by path, so it is actually for the unredirected file.
1761                    // This lets us know if the unredirected file has changed. If it has we should break the redirect.
1762                    if (newSourceFile !== oldSourceFile.redirectInfo.unredirected) {
1763                        // Underlying file has changed. Might not redirect anymore. Must rebuild program.
1764                        return StructureIsReused.Not;
1765                    }
1766                    fileChanged = false;
1767                    newSourceFile = oldSourceFile; // Use the redirect.
1768                }
1769                else if (oldProgram.redirectTargetsMap.has(oldSourceFile.path)) {
1770                    // If a redirected-to source file changes, the redirect may be broken.
1771                    if (newSourceFile !== oldSourceFile) {
1772                        return StructureIsReused.Not;
1773                    }
1774                    fileChanged = false;
1775                }
1776                else {
1777                    fileChanged = newSourceFile !== oldSourceFile;
1778                }
1779
1780                // Since the project references havent changed, its right to set originalFileName and resolvedPath here
1781                newSourceFile.path = oldSourceFile.path;
1782                newSourceFile.originalFileName = oldSourceFile.originalFileName;
1783                newSourceFile.resolvedPath = oldSourceFile.resolvedPath;
1784                newSourceFile.fileName = oldSourceFile.fileName;
1785
1786                const packageName = oldProgram.sourceFileToPackageName.get(oldSourceFile.path);
1787                if (packageName !== undefined) {
1788                    // If there are 2 different source files for the same package name and at least one of them changes,
1789                    // they might become redirects. So we must rebuild the program.
1790                    const prevKind = seenPackageNames.get(packageName);
1791                    const newKind = fileChanged ? SeenPackageName.Modified : SeenPackageName.Exists;
1792                    if ((prevKind !== undefined && newKind === SeenPackageName.Modified) || prevKind === SeenPackageName.Modified) {
1793                        return StructureIsReused.Not;
1794                    }
1795                    seenPackageNames.set(packageName, newKind);
1796                }
1797
1798                if (fileChanged) {
1799                    if (oldSourceFile.impliedNodeFormat !== newSourceFile.impliedNodeFormat) {
1800                        structureIsReused = StructureIsReused.SafeModules;
1801                    }
1802                    // The `newSourceFile` object was created for the new program.
1803                    else if (!arrayIsEqualTo(oldSourceFile.libReferenceDirectives, newSourceFile.libReferenceDirectives, fileReferenceIsEqualTo)) {
1804                        // 'lib' references has changed. Matches behavior in changesAffectModuleResolution
1805                        structureIsReused = StructureIsReused.SafeModules;
1806                    }
1807                    else if (oldSourceFile.hasNoDefaultLib !== newSourceFile.hasNoDefaultLib) {
1808                        // value of no-default-lib has changed
1809                        // this will affect if default library is injected into the list of files
1810                        structureIsReused = StructureIsReused.SafeModules;
1811                    }
1812                    // check tripleslash references
1813                    else if (!arrayIsEqualTo(oldSourceFile.referencedFiles, newSourceFile.referencedFiles, fileReferenceIsEqualTo)) {
1814                        // tripleslash references has changed
1815                        structureIsReused = StructureIsReused.SafeModules;
1816                    }
1817                    else {
1818                        // check imports and module augmentations
1819                        collectExternalModuleReferences(newSourceFile);
1820                        if (!arrayIsEqualTo(oldSourceFile.imports, newSourceFile.imports, moduleNameIsEqualTo)) {
1821                            // imports has changed
1822                            structureIsReused = StructureIsReused.SafeModules;
1823                        }
1824                        else if (!arrayIsEqualTo(oldSourceFile.moduleAugmentations, newSourceFile.moduleAugmentations, moduleNameIsEqualTo)) {
1825                            // moduleAugmentations has changed
1826                            structureIsReused = StructureIsReused.SafeModules;
1827                        }
1828                        else if ((oldSourceFile.flags & NodeFlags.PermanentlySetIncrementalFlags) !== (newSourceFile.flags & NodeFlags.PermanentlySetIncrementalFlags)) {
1829                            // dynamicImport has changed
1830                            structureIsReused = StructureIsReused.SafeModules;
1831                        }
1832                        else if (!arrayIsEqualTo(oldSourceFile.typeReferenceDirectives, newSourceFile.typeReferenceDirectives, fileReferenceIsEqualTo)) {
1833                            // 'types' references has changed
1834                            structureIsReused = StructureIsReused.SafeModules;
1835                        }
1836                    }
1837
1838                    // tentatively approve the file
1839                    modifiedSourceFiles.push({ oldFile: oldSourceFile, newFile: newSourceFile });
1840                }
1841                else if (hasInvalidatedResolutions(oldSourceFile.path)) {
1842                    // 'module/types' references could have changed
1843                    structureIsReused = StructureIsReused.SafeModules;
1844
1845                    // add file to the modified list so that we will resolve it later
1846                    modifiedSourceFiles.push({ oldFile: oldSourceFile, newFile: newSourceFile });
1847                }
1848
1849                // if file has passed all checks it should be safe to reuse it
1850                newSourceFiles.push(newSourceFile);
1851            }
1852
1853            if (structureIsReused !== StructureIsReused.Completely) {
1854                return structureIsReused;
1855            }
1856
1857            const modifiedFiles = modifiedSourceFiles.map(f => f.oldFile);
1858            for (const oldFile of oldSourceFiles) {
1859                if (!contains(modifiedFiles, oldFile)) {
1860                    for (const moduleName of oldFile.ambientModuleNames) {
1861                        ambientModuleNameToUnmodifiedFileName.set(moduleName, oldFile.fileName);
1862                    }
1863                }
1864            }
1865            // try to verify results of module resolution
1866            for (const { oldFile: oldSourceFile, newFile: newSourceFile } of modifiedSourceFiles) {
1867                const moduleNames = getModuleNames(newSourceFile);
1868                const resolutions = resolveModuleNamesReusingOldState(moduleNames, newSourceFile);
1869                // ensure that module resolution results are still correct
1870                const resolutionsChanged = hasChangesInResolutions(moduleNames, resolutions, oldSourceFile.resolvedModules, oldSourceFile, moduleResolutionIsEqualTo);
1871                if (resolutionsChanged) {
1872                    structureIsReused = StructureIsReused.SafeModules;
1873                    newSourceFile.resolvedModules = zipToModeAwareCache(newSourceFile, moduleNames, resolutions);
1874                }
1875                else {
1876                    newSourceFile.resolvedModules = oldSourceFile.resolvedModules;
1877                }
1878                const typesReferenceDirectives = newSourceFile.typeReferenceDirectives;
1879                const typeReferenceResolutions = resolveTypeReferenceDirectiveNamesWorker(typesReferenceDirectives, newSourceFile);
1880                // ensure that types resolutions are still correct
1881                const typeReferenceResolutionsChanged = hasChangesInResolutions(typesReferenceDirectives, typeReferenceResolutions, oldSourceFile.resolvedTypeReferenceDirectiveNames, oldSourceFile, typeDirectiveIsEqualTo);
1882                if (typeReferenceResolutionsChanged) {
1883                    structureIsReused = StructureIsReused.SafeModules;
1884                    newSourceFile.resolvedTypeReferenceDirectiveNames = zipToModeAwareCache(newSourceFile, typesReferenceDirectives, typeReferenceResolutions);
1885                }
1886                else {
1887                    newSourceFile.resolvedTypeReferenceDirectiveNames = oldSourceFile.resolvedTypeReferenceDirectiveNames;
1888                }
1889            }
1890
1891            if (structureIsReused !== StructureIsReused.Completely) {
1892                return structureIsReused;
1893            }
1894
1895            if (changesAffectingProgramStructure(oldOptions, options) || host.hasChangedAutomaticTypeDirectiveNames?.()) {
1896                return StructureIsReused.SafeModules;
1897            }
1898
1899            missingFilePaths = oldProgram.getMissingFilePaths();
1900
1901            // update fileName -> file mapping
1902            Debug.assert(newSourceFiles.length === oldProgram.getSourceFiles().length);
1903            for (const newSourceFile of newSourceFiles) {
1904                filesByName.set(newSourceFile.path, newSourceFile);
1905            }
1906            const oldFilesByNameMap = oldProgram.getFilesByNameMap();
1907            oldFilesByNameMap.forEach((oldFile, path) => {
1908                if (!oldFile) {
1909                    filesByName.set(path, oldFile);
1910                    return;
1911                }
1912                if (oldFile.path === path) {
1913                    // Set the file as found during node modules search if it was found that way in old progra,
1914                    if (oldProgram!.isSourceFileFromExternalLibrary(oldFile)) {
1915                        sourceFilesFoundSearchingNodeModules.set(oldFile.path, true);
1916                    }
1917                    return;
1918                }
1919                filesByName.set(path, filesByName.get(oldFile.path));
1920            });
1921
1922            files = newSourceFiles;
1923            fileReasons = oldProgram.getFileIncludeReasons();
1924            fileProcessingDiagnostics = oldProgram.getFileProcessingDiagnostics();
1925            resolvedTypeReferenceDirectives = oldProgram.getResolvedTypeReferenceDirectives();
1926
1927            sourceFileToPackageName = oldProgram.sourceFileToPackageName;
1928            redirectTargetsMap = oldProgram.redirectTargetsMap;
1929            usesUriStyleNodeCoreModules = oldProgram.usesUriStyleNodeCoreModules;
1930
1931            return StructureIsReused.Completely;
1932        }
1933
1934        function getEmitHost(writeFileCallback?: WriteFileCallback): EmitHost {
1935            return {
1936                getPrependNodes,
1937                getCanonicalFileName,
1938                getCommonSourceDirectory: program.getCommonSourceDirectory,
1939                getCompilerOptions: program.getCompilerOptions,
1940                getCurrentDirectory: () => currentDirectory,
1941                getNewLine: () => host.getNewLine(),
1942                getSourceFile: program.getSourceFile,
1943                getSourceFileByPath: program.getSourceFileByPath,
1944                getSourceFiles: program.getSourceFiles,
1945                getLibFileFromReference: program.getLibFileFromReference,
1946                isSourceFileFromExternalLibrary,
1947                getResolvedProjectReferenceToRedirect,
1948                getProjectReferenceRedirect,
1949                isSourceOfProjectReferenceRedirect,
1950                getSymlinkCache,
1951                writeFile: writeFileCallback || writeFile,
1952                isEmitBlocked,
1953                readFile: f => host.readFile(f),
1954                fileExists: f => {
1955                    // Use local caches
1956                    const path = toPath(f);
1957                    if (getSourceFileByPath(path)) return true;
1958                    if (contains(missingFilePaths, path)) return false;
1959                    // Before falling back to the host
1960                    return host.fileExists(f);
1961                },
1962                useCaseSensitiveFileNames: () => host.useCaseSensitiveFileNames(),
1963                getProgramBuildInfo: () => program.getProgramBuildInfo && program.getProgramBuildInfo(),
1964                getSourceFileFromReference: (file, ref) => program.getSourceFileFromReference(file, ref),
1965                redirectTargetsMap,
1966                getFileIncludeReasons: program.getFileIncludeReasons,
1967                createHash: maybeBind(host, host.createHash),
1968            };
1969        }
1970
1971        function writeFile(
1972            fileName: string,
1973            text: string,
1974            writeByteOrderMark: boolean,
1975            onError?: (message: string) => void,
1976            sourceFiles?: readonly SourceFile[],
1977            data?: WriteFileCallbackData
1978        ) {
1979            host.writeFile(fileName, text, writeByteOrderMark, onError, sourceFiles, data);
1980        }
1981
1982        function emitBuildInfo(writeFileCallback?: WriteFileCallback): EmitResult {
1983            Debug.assert(!outFile(options));
1984            tracing?.push(tracing.Phase.Emit, "emitBuildInfo", {}, /*separateBeginAndEnd*/ true);
1985            performance.mark("beforeEmit");
1986            const emitResult = emitFiles(
1987                notImplementedResolver,
1988                getEmitHost(writeFileCallback),
1989                /*targetSourceFile*/ undefined,
1990                /*transformers*/ noTransformers,
1991                /*emitOnlyDtsFiles*/ false,
1992                /*onlyBuildInfo*/ true
1993            );
1994
1995            performance.mark("afterEmit");
1996            performance.measure("Emit", "beforeEmit", "afterEmit");
1997            tracing?.pop();
1998            return emitResult;
1999        }
2000
2001        function getResolvedProjectReferences() {
2002            return resolvedProjectReferences;
2003        }
2004
2005        function getProjectReferences() {
2006            return projectReferences;
2007        }
2008
2009        function getPrependNodes() {
2010            return createPrependNodes(
2011                projectReferences,
2012                (_ref, index) => resolvedProjectReferences![index]?.commandLine,
2013                fileName => {
2014                    const path = toPath(fileName);
2015                    const sourceFile = getSourceFileByPath(path);
2016                    return sourceFile ? sourceFile.text : filesByName.has(path) ? undefined : host.readFile(path);
2017                }
2018            );
2019        }
2020
2021        function isSourceFileFromExternalLibrary(file: SourceFile): boolean {
2022            return !!sourceFilesFoundSearchingNodeModules.get(file.path);
2023        }
2024
2025        function isSourceFileDefaultLibrary(file: SourceFile): boolean {
2026            if (!file.isDeclarationFile) {
2027                return false;
2028            }
2029
2030            if (file.hasNoDefaultLib) {
2031                return true;
2032            }
2033
2034            if (!options.noLib) {
2035                return false;
2036            }
2037
2038            // If '--lib' is not specified, include default library file according to '--target'
2039            // otherwise, using options specified in '--lib' instead of '--target' default library file
2040            const equalityComparer = host.useCaseSensitiveFileNames() ? equateStringsCaseSensitive : equateStringsCaseInsensitive;
2041            if (!options.lib) {
2042                return equalityComparer(file.fileName, getDefaultLibraryFileName());
2043            }
2044            else {
2045                return some(options.lib, libFileName => equalityComparer(file.fileName, pathForLibFile(libFileName)));
2046            }
2047        }
2048
2049        function getEtsLibSFromProgram() {
2050            return getEtsLibs(program);
2051        }
2052
2053        function getTypeChecker() {
2054            return typeChecker || (typeChecker = createTypeChecker(program));
2055        }
2056
2057        function emit(sourceFile?: SourceFile, writeFileCallback?: WriteFileCallback, cancellationToken?: CancellationToken, emitOnlyDtsFiles?: boolean, transformers?: CustomTransformers, forceDtsEmit?: boolean): EmitResult {
2058            tracing?.push(tracing.Phase.Emit, "emit", { path: sourceFile?.path }, /*separateBeginAndEnd*/ true);
2059            const result = runWithCancellationToken(() => emitWorker(program, sourceFile, writeFileCallback, cancellationToken, emitOnlyDtsFiles, transformers, forceDtsEmit));
2060            tracing?.pop();
2061            return result;
2062        }
2063
2064        function isEmitBlocked(emitFileName: string): boolean {
2065            return hasEmitBlockingDiagnostics.has(toPath(emitFileName));
2066        }
2067
2068        function emitWorker(program: Program, sourceFile: SourceFile | undefined, writeFileCallback: WriteFileCallback | undefined, cancellationToken: CancellationToken | undefined, emitOnlyDtsFiles?: boolean, customTransformers?: CustomTransformers, forceDtsEmit?: boolean): EmitResult {
2069            if (!forceDtsEmit) {
2070                const result = handleNoEmitOptions(program, sourceFile, writeFileCallback, cancellationToken);
2071                if (result) return result;
2072            }
2073
2074            // Create the emit resolver outside of the "emitTime" tracking code below.  That way
2075            // any cost associated with it (like type checking) are appropriate associated with
2076            // the type-checking counter.
2077            //
2078            // If the -out option is specified, we should not pass the source file to getEmitResolver.
2079            // This is because in the -out scenario all files need to be emitted, and therefore all
2080            // files need to be type checked. And the way to specify that all files need to be type
2081            // checked is to not pass the file to getEmitResolver.
2082            const emitResolver = getTypeChecker().getEmitResolver(outFile(options) ? undefined : sourceFile, cancellationToken);
2083
2084            performance.mark("beforeEmit");
2085
2086            const emitResult = emitFiles(
2087                emitResolver,
2088                getEmitHost(writeFileCallback),
2089                sourceFile,
2090                getTransformers(options, customTransformers, emitOnlyDtsFiles),
2091                emitOnlyDtsFiles,
2092                /*onlyBuildInfo*/ false,
2093                forceDtsEmit
2094            );
2095
2096            performance.mark("afterEmit");
2097            performance.measure("Emit", "beforeEmit", "afterEmit");
2098            return emitResult;
2099        }
2100
2101        function getSourceFile(fileName: string): SourceFile | undefined {
2102            return getSourceFileByPath(toPath(fileName));
2103        }
2104
2105        function getSourceFileByPath(path: Path): SourceFile | undefined {
2106            return filesByName.get(path) || undefined;
2107        }
2108
2109        function getDiagnosticsHelper<T extends Diagnostic>(
2110            sourceFile: SourceFile | undefined,
2111            getDiagnostics: (sourceFile: SourceFile, cancellationToken: CancellationToken | undefined) => readonly T[],
2112            cancellationToken: CancellationToken | undefined): readonly T[] {
2113            if (sourceFile) {
2114                return getDiagnostics(sourceFile, cancellationToken);
2115            }
2116            return sortAndDeduplicateDiagnostics(flatMap(program.getSourceFiles(), sourceFile => {
2117                if (cancellationToken) {
2118                    cancellationToken.throwIfCancellationRequested();
2119                }
2120                return getDiagnostics(sourceFile, cancellationToken);
2121            }));
2122        }
2123
2124        function getSyntacticDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): readonly DiagnosticWithLocation[] {
2125            return getDiagnosticsHelper(sourceFile, getSyntacticDiagnosticsForFile, cancellationToken);
2126        }
2127
2128        function getSemanticDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): readonly Diagnostic[] {
2129            return getDiagnosticsHelper(sourceFile, getSemanticDiagnosticsForFile, cancellationToken);
2130        }
2131
2132        function getCachedSemanticDiagnostics(sourceFile?: SourceFile): readonly Diagnostic[] | undefined {
2133           return sourceFile
2134                ? cachedBindAndCheckDiagnosticsForFile.perFile?.get(sourceFile.path)
2135                : cachedBindAndCheckDiagnosticsForFile.allDiagnostics;
2136        }
2137
2138        function getBindAndCheckDiagnostics(sourceFile: SourceFile, cancellationToken?: CancellationToken): readonly Diagnostic[] {
2139            return getBindAndCheckDiagnosticsForFile(sourceFile, cancellationToken);
2140        }
2141
2142        function getProgramDiagnostics(sourceFile: SourceFile): readonly Diagnostic[] {
2143            if (skipTypeChecking(sourceFile, options, program) || (sourceFile.isDeclarationFile && !!options.needDoArkTsLinter)) {
2144                return emptyArray;
2145            }
2146
2147            const programDiagnosticsInFile = programDiagnostics.getDiagnostics(sourceFile.fileName);
2148            if (!sourceFile.commentDirectives?.length) {
2149                return programDiagnosticsInFile;
2150            }
2151
2152            return getDiagnosticsWithPrecedingDirectives(sourceFile, sourceFile.commentDirectives, programDiagnosticsInFile).diagnostics;
2153        }
2154
2155        function getDeclarationDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): readonly DiagnosticWithLocation[] {
2156            const options = program.getCompilerOptions();
2157            // collect diagnostics from the program only once if either no source file was specified or out/outFile is set (bundled emit)
2158            if (!sourceFile || outFile(options)) {
2159                return getDeclarationDiagnosticsWorker(sourceFile, cancellationToken);
2160            }
2161            else {
2162                return getDiagnosticsHelper(sourceFile, getDeclarationDiagnosticsForFile, cancellationToken);
2163            }
2164        }
2165
2166        function getSyntacticDiagnosticsForFile(sourceFile: SourceFile): readonly DiagnosticWithLocation[] {
2167            // For JavaScript files, we report semantic errors for using TypeScript-only
2168            // constructs from within a JavaScript file as syntactic errors.
2169            if (isSourceFileJS(sourceFile)) {
2170                if (!sourceFile.additionalSyntacticDiagnostics) {
2171                    sourceFile.additionalSyntacticDiagnostics = getJSSyntacticDiagnosticsForFile(sourceFile);
2172                }
2173                return concatenate(sourceFile.additionalSyntacticDiagnostics, sourceFile.parseDiagnostics);
2174            }
2175            return sourceFile.parseDiagnostics;
2176        }
2177
2178        function runWithCancellationToken<T>(func: () => T): T {
2179            try {
2180                return func();
2181            }
2182            catch (e) {
2183                if (e instanceof OperationCanceledException) {
2184                    // We were canceled while performing the operation.  Because our type checker
2185                    // might be a bad state, we need to throw it away.
2186                    typeChecker = undefined!;
2187                }
2188
2189                throw e;
2190            }
2191        }
2192
2193        function getSemanticDiagnosticsForFile(sourceFile: SourceFile, cancellationToken: CancellationToken | undefined): readonly Diagnostic[] {
2194            return concatenate(
2195                filterSemanticDiagnostics(getBindAndCheckDiagnosticsForFile(sourceFile, cancellationToken), options),
2196                getProgramDiagnostics(sourceFile)
2197            );
2198        }
2199
2200        function getBindAndCheckDiagnosticsForFile(sourceFile: SourceFile, cancellationToken: CancellationToken | undefined): readonly Diagnostic[] {
2201            return getAndCacheDiagnostics(sourceFile, cancellationToken, cachedBindAndCheckDiagnosticsForFile, getBindAndCheckDiagnosticsForFileNoCache);
2202        }
2203
2204        function getBindAndCheckDiagnosticsForFileNoCache(sourceFile: SourceFile, cancellationToken: CancellationToken | undefined): readonly Diagnostic[] {
2205            return runWithCancellationToken(() => {
2206                // Only check and block .d.ts import .ets behavior when it is called by "ets-loader" and scanned.
2207                const filterFlag = !!options.needDoArkTsLinter;
2208
2209                if (filterFlag) {
2210                    options.skipLibCheck = false;
2211                }
2212
2213                if (skipTypeChecking(sourceFile, options, program)) {
2214                    return emptyArray;
2215                }
2216
2217                const typeChecker = getTypeChecker();
2218
2219                Debug.assert(!!sourceFile.bindDiagnostics);
2220
2221                const isJs = sourceFile.scriptKind === ScriptKind.JS || sourceFile.scriptKind === ScriptKind.JSX;
2222                const isCheckJs = isJs && isCheckJsEnabledForFile(sourceFile, options);
2223                const isPlainJs = isPlainJsFile(sourceFile, options.checkJs);
2224                const isTsNoCheck = !!sourceFile.checkJsDirective && sourceFile.checkJsDirective.enabled === false;
2225
2226                // By default, only type-check .ts, .tsx, Deferred, plain JS, checked JS and External
2227                // - plain JS: .js files with no // ts-check and checkJs: undefined
2228                // - check JS: .js files with either // ts-check or checkJs: true
2229                // - external: files that are added by plugins
2230                const includeBindAndCheckDiagnostics = !isTsNoCheck && (sourceFile.scriptKind === ScriptKind.TS || sourceFile.scriptKind === ScriptKind.TSX
2231                        || sourceFile.scriptKind === ScriptKind.External || isPlainJs || isCheckJs || sourceFile.scriptKind === ScriptKind.Deferred || sourceFile.scriptKind === ScriptKind.ETS);
2232                let bindDiagnostics: readonly Diagnostic[] = includeBindAndCheckDiagnostics ? sourceFile.bindDiagnostics : emptyArray;
2233                let checkDiagnostics = includeBindAndCheckDiagnostics ? typeChecker.getDiagnostics(sourceFile, cancellationToken) : emptyArray;
2234                if (isPlainJs) {
2235                    bindDiagnostics = filter(bindDiagnostics, d => plainJSErrors.has(d.code));
2236                    checkDiagnostics = filter(checkDiagnostics, d => plainJSErrors.has(d.code));
2237                }
2238                // skip ts-expect-error errors in plain JS files, and skip JSDoc errors except in checked JS
2239                return getMergedBindAndCheckDiagnostics(sourceFile, includeBindAndCheckDiagnostics && !isPlainJs, bindDiagnostics,
2240                    filterFlag ? filterDiagnostics(checkDiagnostics) : checkDiagnostics, isCheckJs ? sourceFile.jsDocDiagnostics : undefined);
2241            });
2242        }
2243
2244        function filterDiagnostics(allDiagnostics: (readonly Diagnostic[] | undefined)): readonly Diagnostic[] | undefined {
2245            if (allDiagnostics) {
2246                const diagnosticsAfterFilter = allDiagnostics.filter((item) => {
2247                    /* Diagnostics suppression scheme:
2248                     *   1.if `file` comes from `oh_modules`:
2249                     *        skip all the diagnostics in declaration files and importing ArkTS errors from TS files
2250                     *        done.
2251                     *   2.if `file` is a d.ts:
2252                     *        if d.ts is a kit declaration which being named with `@kit.` prefix:
2253                     *            skip all the diagnostics.
2254                     *        else:
2255                     *            skip all the diagnostics other than forbidden imports.
2256                     *        done.
2257                     */
2258                    const isOhModule = (item.file !== undefined) && (normalizePath(item.file.fileName).indexOf("/oh_modules/") !== -1);
2259                    const isNotForbiddenImportDiag = item.messageText !== (options.isCompatibleVersion ?
2260                        Diagnostics.Importing_ArkTS_files_in_JS_and_TS_files_is_about_to_be_forbidden.message :
2261                        Diagnostics.Importing_ArkTS_files_in_JS_and_TS_files_is_forbidden.message);
2262
2263                    if (isOhModule) {
2264                        if (options.skipTscOhModuleCheck) {
2265                            return false;
2266                        }
2267                        if (item.file?.isDeclarationFile) {
2268                            return false;
2269                        }
2270                        return isNotForbiddenImportDiag;
2271                    }
2272
2273                    if (item.file?.scriptKind === ScriptKind.TS && item.file?.isDeclarationFile) {
2274                        if (item.file !== undefined && getBaseFileName(item.file.fileName).indexOf('@kit.') === 0) {
2275                            // kit declaration
2276                            return false;
2277                        }
2278                        return !isNotForbiddenImportDiag;
2279                    }
2280                    return true;
2281                });
2282                return diagnosticsAfterFilter;
2283            }
2284            return emptyArray;
2285        }
2286
2287        function getMergedBindAndCheckDiagnostics(sourceFile: SourceFile, includeBindAndCheckDiagnostics: boolean, ...allDiagnostics: (readonly Diagnostic[] | undefined)[]) {
2288            const flatDiagnostics = flatten(allDiagnostics);
2289            if (!includeBindAndCheckDiagnostics || !sourceFile.commentDirectives?.length) {
2290                return flatDiagnostics;
2291            }
2292
2293            const { diagnostics, directives } = getDiagnosticsWithPrecedingDirectives(sourceFile, sourceFile.commentDirectives, flatDiagnostics);
2294
2295            for (const errorExpectation of directives.getUnusedExpectations()) {
2296                diagnostics.push(createDiagnosticForRange(sourceFile, errorExpectation.range, Diagnostics.Unused_ts_expect_error_directive));
2297            }
2298
2299            return diagnostics;
2300        }
2301
2302        /**
2303         * Creates a map of comment directives along with the diagnostics immediately preceded by one of them.
2304         * Comments that match to any of those diagnostics are marked as used.
2305         */
2306        function getDiagnosticsWithPrecedingDirectives(sourceFile: SourceFile, commentDirectives: CommentDirective[], flatDiagnostics: Diagnostic[]) {
2307            // Diagnostics are only reported if there is no comment directive preceding them
2308            // This will modify the directives map by marking "used" ones with a corresponding diagnostic
2309            const directives = createCommentDirectivesMap(sourceFile, commentDirectives);
2310            const diagnostics = flatDiagnostics.filter(diagnostic => markPrecedingCommentDirectiveLine(diagnostic, directives) === -1);
2311
2312            return { diagnostics, directives };
2313        }
2314
2315        function getSuggestionDiagnostics(sourceFile: SourceFile, cancellationToken: CancellationToken): readonly DiagnosticWithLocation[] {
2316            return runWithCancellationToken(() => {
2317                return getTypeChecker().getSuggestionDiagnostics(sourceFile, cancellationToken);
2318            });
2319        }
2320
2321        /**
2322         * @returns The line index marked as preceding the diagnostic, or -1 if none was.
2323         */
2324        function markPrecedingCommentDirectiveLine(diagnostic: Diagnostic, directives: CommentDirectivesMap) {
2325            const { file, start } = diagnostic;
2326            if (!file) {
2327                return -1;
2328            }
2329
2330            // Start out with the line just before the text
2331            const lineStarts = getLineStarts(file);
2332            let line = computeLineAndCharacterOfPosition(lineStarts, start!).line - 1; // TODO: GH#18217
2333            while (line >= 0) {
2334                // As soon as that line is known to have a comment directive, use that
2335                if (directives.markUsed(line)) {
2336                    return line;
2337                }
2338
2339                // Stop searching if the line is not empty and not a comment
2340                const lineText = file.text.slice(lineStarts[line], lineStarts[line + 1]).trim();
2341                if (lineText !== "" && !/^(\s*)\/\/(.*)$/.test(lineText)) {
2342                    return -1;
2343                }
2344
2345                line--;
2346            }
2347
2348            return -1;
2349        }
2350
2351        function getJSSyntacticDiagnosticsForFile(sourceFile: SourceFile): DiagnosticWithLocation[] {
2352            return runWithCancellationToken(() => {
2353                const diagnostics: DiagnosticWithLocation[] = [];
2354                walk(sourceFile, sourceFile);
2355                forEachChildRecursively(sourceFile, walk, walkArray);
2356
2357                return diagnostics;
2358
2359                function walk(node: Node, parent: Node) {
2360                    // Return directly from the case if the given node doesnt want to visit each child
2361                    // Otherwise break to visit each child
2362
2363                    switch (parent.kind) {
2364                        case SyntaxKind.Parameter:
2365                        case SyntaxKind.PropertyDeclaration:
2366                        case SyntaxKind.MethodDeclaration:
2367                            if ((parent as ParameterDeclaration | PropertyDeclaration | MethodDeclaration).questionToken === node) {
2368                                diagnostics.push(createDiagnosticForNode(node, Diagnostics.The_0_modifier_can_only_be_used_in_TypeScript_files, "?"));
2369                                return "skip";
2370                            }
2371                        // falls through
2372                        case SyntaxKind.MethodSignature:
2373                        case SyntaxKind.Constructor:
2374                        case SyntaxKind.GetAccessor:
2375                        case SyntaxKind.SetAccessor:
2376                        case SyntaxKind.FunctionExpression:
2377                        case SyntaxKind.FunctionDeclaration:
2378                        case SyntaxKind.ArrowFunction:
2379                        case SyntaxKind.VariableDeclaration:
2380                            // type annotation
2381                            if ((parent as FunctionLikeDeclaration | VariableDeclaration | ParameterDeclaration | PropertyDeclaration).type === node) {
2382                                diagnostics.push(createDiagnosticForNode(node, Diagnostics.Type_annotations_can_only_be_used_in_TypeScript_files));
2383                                return "skip";
2384                            }
2385                    }
2386
2387                    switch (node.kind) {
2388                        case SyntaxKind.ImportClause:
2389                            if ((node as ImportClause).isTypeOnly) {
2390                                diagnostics.push(createDiagnosticForNode(parent, Diagnostics._0_declarations_can_only_be_used_in_TypeScript_files, "import type"));
2391                                return "skip";
2392                            }
2393                            break;
2394                        case SyntaxKind.ExportDeclaration:
2395                            if ((node as ExportDeclaration).isTypeOnly) {
2396                                diagnostics.push(createDiagnosticForNode(node, Diagnostics._0_declarations_can_only_be_used_in_TypeScript_files, "export type"));
2397                                return "skip";
2398                            }
2399                            break;
2400                        case SyntaxKind.ImportSpecifier:
2401                        case SyntaxKind.ExportSpecifier:
2402                            if ((node as ImportOrExportSpecifier).isTypeOnly) {
2403                                diagnostics.push(createDiagnosticForNode(node, Diagnostics._0_declarations_can_only_be_used_in_TypeScript_files, isImportSpecifier(node) ? "import...type" : "export...type"));
2404                                return "skip";
2405                            }
2406                            break;
2407                        case SyntaxKind.ImportEqualsDeclaration:
2408                            diagnostics.push(createDiagnosticForNode(node, Diagnostics.import_can_only_be_used_in_TypeScript_files));
2409                            return "skip";
2410                        case SyntaxKind.ExportAssignment:
2411                            if ((node as ExportAssignment).isExportEquals) {
2412                                diagnostics.push(createDiagnosticForNode(node, Diagnostics.export_can_only_be_used_in_TypeScript_files));
2413                                return "skip";
2414                            }
2415                            break;
2416                        case SyntaxKind.HeritageClause:
2417                            const heritageClause = node as HeritageClause;
2418                            if (heritageClause.token === SyntaxKind.ImplementsKeyword) {
2419                                diagnostics.push(createDiagnosticForNode(node, Diagnostics.implements_clauses_can_only_be_used_in_TypeScript_files));
2420                                return "skip";
2421                            }
2422                            break;
2423                        case SyntaxKind.InterfaceDeclaration:
2424                            const interfaceKeyword = tokenToString(SyntaxKind.InterfaceKeyword);
2425                            Debug.assertIsDefined(interfaceKeyword);
2426                            diagnostics.push(createDiagnosticForNode(node, Diagnostics._0_declarations_can_only_be_used_in_TypeScript_files, interfaceKeyword));
2427                            return "skip";
2428                        case SyntaxKind.ModuleDeclaration:
2429                            const moduleKeyword = node.flags & NodeFlags.Namespace ? tokenToString(SyntaxKind.NamespaceKeyword) : tokenToString(SyntaxKind.ModuleKeyword);
2430                            Debug.assertIsDefined(moduleKeyword);
2431                            diagnostics.push(createDiagnosticForNode(node, Diagnostics._0_declarations_can_only_be_used_in_TypeScript_files, moduleKeyword));
2432                            return "skip";
2433                        case SyntaxKind.TypeAliasDeclaration:
2434                            diagnostics.push(createDiagnosticForNode(node, Diagnostics.Type_aliases_can_only_be_used_in_TypeScript_files));
2435                            return "skip";
2436                        case SyntaxKind.EnumDeclaration:
2437                            const enumKeyword = Debug.checkDefined(tokenToString(SyntaxKind.EnumKeyword));
2438                            diagnostics.push(createDiagnosticForNode(node, Diagnostics._0_declarations_can_only_be_used_in_TypeScript_files, enumKeyword));
2439                            return "skip";
2440                        case SyntaxKind.NonNullExpression:
2441                            diagnostics.push(createDiagnosticForNode(node, Diagnostics.Non_null_assertions_can_only_be_used_in_TypeScript_files));
2442                            return "skip";
2443                        case SyntaxKind.AsExpression:
2444                            diagnostics.push(createDiagnosticForNode((node as AsExpression).type, Diagnostics.Type_assertion_expressions_can_only_be_used_in_TypeScript_files));
2445                            return "skip";
2446                        case SyntaxKind.SatisfiesExpression:
2447                            diagnostics.push(createDiagnosticForNode((node as SatisfiesExpression).type, Diagnostics.Type_satisfaction_expressions_can_only_be_used_in_TypeScript_files));
2448                            return "skip";
2449                        case SyntaxKind.TypeAssertionExpression:
2450                            Debug.fail(); // Won't parse these in a JS file anyway, as they are interpreted as JSX.
2451                    }
2452                }
2453
2454                function walkArray(nodes: NodeArray<Node>, parent: Node) {
2455                    if (canHaveModifiers(parent) && parent.modifiers === nodes && some(nodes, isDecorator) && !options.experimentalDecorators) {
2456                        diagnostics.push(createDiagnosticForNode(parent, Diagnostics.Experimental_support_for_decorators_is_a_feature_that_is_subject_to_change_in_a_future_release_Set_the_experimentalDecorators_option_in_your_tsconfig_or_jsconfig_to_remove_this_warning));
2457                    }
2458
2459                    switch (parent.kind) {
2460                        case SyntaxKind.ClassDeclaration:
2461                        case SyntaxKind.ClassExpression:
2462                        case SyntaxKind.StructDeclaration:
2463                        case SyntaxKind.MethodDeclaration:
2464                        case SyntaxKind.Constructor:
2465                        case SyntaxKind.GetAccessor:
2466                        case SyntaxKind.SetAccessor:
2467                        case SyntaxKind.FunctionExpression:
2468                        case SyntaxKind.FunctionDeclaration:
2469                        case SyntaxKind.ArrowFunction:
2470                            // Check type parameters
2471                            if (nodes === (parent as DeclarationWithTypeParameterChildren).typeParameters) {
2472                                diagnostics.push(createDiagnosticForNodeArray(nodes, Diagnostics.Type_parameter_declarations_can_only_be_used_in_TypeScript_files));
2473                                return "skip";
2474                            }
2475                        // falls through
2476
2477                        case SyntaxKind.VariableStatement:
2478                            // Check modifiers
2479                            if (nodes === (parent as VariableStatement).modifiers) {
2480                                checkModifiers((parent as VariableStatement).modifiers!, parent.kind === SyntaxKind.VariableStatement);
2481                                return "skip";
2482                            }
2483                            break;
2484                        case SyntaxKind.PropertyDeclaration:
2485                            // Check modifiers of property declaration
2486                            if (nodes === (parent as PropertyDeclaration).modifiers) {
2487                                for (const modifier of nodes as NodeArray<ModifierLike>) {
2488                                    if (isModifier(modifier)
2489                                        && modifier.kind !== SyntaxKind.StaticKeyword
2490                                        && modifier.kind !== SyntaxKind.AccessorKeyword) {
2491                                        diagnostics.push(createDiagnosticForNode(modifier, Diagnostics.The_0_modifier_can_only_be_used_in_TypeScript_files, tokenToString(modifier.kind)));
2492                                    }
2493                                }
2494                                return "skip";
2495                            }
2496                            break;
2497                        case SyntaxKind.Parameter:
2498                            // Check modifiers of parameter declaration
2499                            if (nodes === (parent as ParameterDeclaration).modifiers && some(nodes, isModifier)) {
2500                                diagnostics.push(createDiagnosticForNodeArray(nodes, Diagnostics.Parameter_modifiers_can_only_be_used_in_TypeScript_files));
2501                                return "skip";
2502                            }
2503                            break;
2504                        case SyntaxKind.CallExpression:
2505                        case SyntaxKind.NewExpression:
2506                        case SyntaxKind.ExpressionWithTypeArguments:
2507                        case SyntaxKind.JsxSelfClosingElement:
2508                        case SyntaxKind.JsxOpeningElement:
2509                        case SyntaxKind.TaggedTemplateExpression:
2510                            // Check type arguments
2511                            if (nodes === (parent as NodeWithTypeArguments).typeArguments) {
2512                                diagnostics.push(createDiagnosticForNodeArray(nodes, Diagnostics.Type_arguments_can_only_be_used_in_TypeScript_files));
2513                                return "skip";
2514                            }
2515                            break;
2516                    }
2517                }
2518
2519                function checkModifiers(modifiers: NodeArray<ModifierLike>, isConstValid: boolean) {
2520                    for (const modifier of modifiers) {
2521                        switch (modifier.kind) {
2522                            case SyntaxKind.ConstKeyword:
2523                                if (isConstValid) {
2524                                    continue;
2525                                }
2526                            // to report error,
2527                            // falls through
2528                            case SyntaxKind.PublicKeyword:
2529                            case SyntaxKind.PrivateKeyword:
2530                            case SyntaxKind.ProtectedKeyword:
2531                            case SyntaxKind.ReadonlyKeyword:
2532                            case SyntaxKind.DeclareKeyword:
2533                            case SyntaxKind.AbstractKeyword:
2534                            case SyntaxKind.OverrideKeyword:
2535                            case SyntaxKind.InKeyword:
2536                            case SyntaxKind.OutKeyword:
2537                                diagnostics.push(createDiagnosticForNode(modifier, Diagnostics.The_0_modifier_can_only_be_used_in_TypeScript_files, tokenToString(modifier.kind)));
2538                                break;
2539
2540                            // These are all legal modifiers.
2541                            case SyntaxKind.StaticKeyword:
2542                            case SyntaxKind.ExportKeyword:
2543                            case SyntaxKind.DefaultKeyword:
2544                            case SyntaxKind.AccessorKeyword:
2545                        }
2546                    }
2547                }
2548
2549                function createDiagnosticForNodeArray(nodes: NodeArray<Node>, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number): DiagnosticWithLocation {
2550                    const start = nodes.pos;
2551                    return createFileDiagnostic(sourceFile, start, nodes.end - start, message, arg0, arg1, arg2);
2552                }
2553
2554                // Since these are syntactic diagnostics, parent might not have been set
2555                // this means the sourceFile cannot be infered from the node
2556                function createDiagnosticForNode(node: Node, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number): DiagnosticWithLocation {
2557                    return createDiagnosticForNodeInSourceFile(sourceFile, node, message, arg0, arg1, arg2);
2558                }
2559            });
2560        }
2561
2562        function getDeclarationDiagnosticsWorker(sourceFile: SourceFile | undefined, cancellationToken: CancellationToken | undefined): readonly DiagnosticWithLocation[] {
2563            return getAndCacheDiagnostics(sourceFile, cancellationToken, cachedDeclarationDiagnosticsForFile, getDeclarationDiagnosticsForFileNoCache);
2564        }
2565
2566        function getDeclarationDiagnosticsForFileNoCache(sourceFile: SourceFile | undefined, cancellationToken: CancellationToken | undefined): readonly DiagnosticWithLocation[] {
2567            return runWithCancellationToken(() => {
2568                const resolver = getTypeChecker().getEmitResolver(sourceFile, cancellationToken);
2569                // Don't actually write any files since we're just getting diagnostics.
2570                return ts.getDeclarationDiagnostics(getEmitHost(noop), resolver, sourceFile) || emptyArray;
2571            });
2572        }
2573
2574        function getAndCacheDiagnostics<T extends SourceFile | undefined, U extends Diagnostic>(
2575            sourceFile: T,
2576            cancellationToken: CancellationToken | undefined,
2577            cache: DiagnosticCache<U>,
2578            getDiagnostics: (sourceFile: T, cancellationToken: CancellationToken | undefined) => readonly U[],
2579        ): readonly U[] {
2580
2581            const cachedResult = sourceFile
2582                ? cache.perFile?.get(sourceFile.path)
2583                : cache.allDiagnostics;
2584
2585            if (cachedResult) {
2586                return cachedResult;
2587            }
2588            const result = getDiagnostics(sourceFile, cancellationToken);
2589            if (sourceFile) {
2590                (cache.perFile || (cache.perFile = new Map())).set(sourceFile.path, result);
2591            }
2592            else {
2593                cache.allDiagnostics = result;
2594            }
2595            return result;
2596        }
2597
2598        function getDeclarationDiagnosticsForFile(sourceFile: SourceFile, cancellationToken: CancellationToken): readonly DiagnosticWithLocation[] {
2599            return sourceFile.isDeclarationFile ? [] : getDeclarationDiagnosticsWorker(sourceFile, cancellationToken);
2600        }
2601
2602        function getOptionsDiagnostics(): SortedReadonlyArray<Diagnostic> {
2603            return sortAndDeduplicateDiagnostics(concatenate(
2604                programDiagnostics.getGlobalDiagnostics(),
2605                getOptionsDiagnosticsOfConfigFile()
2606            ));
2607        }
2608
2609        function getOptionsDiagnosticsOfConfigFile() {
2610            if (!options.configFile) return emptyArray;
2611            let diagnostics = programDiagnostics.getDiagnostics(options.configFile.fileName);
2612            forEachResolvedProjectReference(resolvedRef => {
2613                diagnostics = concatenate(diagnostics, programDiagnostics.getDiagnostics(resolvedRef.sourceFile.fileName));
2614            });
2615            return diagnostics;
2616        }
2617
2618        function getGlobalDiagnostics(): SortedReadonlyArray<Diagnostic> {
2619            return rootNames.length ? sortAndDeduplicateDiagnostics(getTypeChecker().getGlobalDiagnostics().slice()) : emptyArray as any as SortedReadonlyArray<Diagnostic>;
2620        }
2621
2622        function getConfigFileParsingDiagnostics(): readonly Diagnostic[] {
2623            return configFileParsingDiagnostics || emptyArray;
2624        }
2625
2626        function processRootFile(fileName: string, isDefaultLib: boolean, ignoreNoDefaultLib: boolean, reason: FileIncludeReason) {
2627            processSourceFile(normalizePath(fileName), isDefaultLib, ignoreNoDefaultLib, /*packageId*/ undefined, reason);
2628        }
2629
2630        function fileReferenceIsEqualTo(a: FileReference, b: FileReference): boolean {
2631            return a.fileName === b.fileName;
2632        }
2633
2634        function moduleNameIsEqualTo(a: StringLiteralLike | Identifier, b: StringLiteralLike | Identifier): boolean {
2635            return a.kind === SyntaxKind.Identifier
2636                ? b.kind === SyntaxKind.Identifier && a.escapedText === b.escapedText
2637                : b.kind === SyntaxKind.StringLiteral && a.text === b.text;
2638        }
2639
2640        function createSyntheticImport(text: string, file: SourceFile) {
2641            const externalHelpersModuleReference = factory.createStringLiteral(text);
2642            const importDecl = factory.createImportDeclaration(/*modifiers*/ undefined, /*importClause*/ undefined, externalHelpersModuleReference, /*assertClause*/ undefined);
2643            addEmitFlags(importDecl, EmitFlags.NeverApplyImportHelper);
2644            setParent(externalHelpersModuleReference, importDecl);
2645            setParent(importDecl, file);
2646            // explicitly unset the synthesized flag on these declarations so the checker API will answer questions about them
2647            // (which is required to build the dependency graph for incremental emit)
2648            (externalHelpersModuleReference as Mutable<Node>).flags &= ~NodeFlags.Synthesized;
2649            (importDecl as Mutable<Node>).flags &= ~NodeFlags.Synthesized;
2650            return externalHelpersModuleReference;
2651        }
2652
2653        function collectExternalModuleReferences(file: SourceFile): void {
2654            if (file.imports) {
2655                return;
2656            }
2657
2658            const isJavaScriptFile = isSourceFileJS(file);
2659            const isExternalModuleFile = isExternalModule(file);
2660
2661            // file.imports may not be undefined if there exists dynamic import
2662            let imports: StringLiteralLike[] | undefined;
2663            let moduleAugmentations: (StringLiteral | Identifier)[] | undefined;
2664            let ambientModules: string[] | undefined;
2665
2666            // If we are importing helpers, we need to add a synthetic reference to resolve the
2667            // helpers library.
2668            if ((options.isolatedModules || isExternalModuleFile)
2669                && !file.isDeclarationFile) {
2670                if (options.importHelpers) {
2671                    // synthesize 'import "tslib"' declaration
2672                    imports = [createSyntheticImport(externalHelpersModuleNameText, file)];
2673                }
2674                const jsxImport = getJSXRuntimeImport(getJSXImplicitImportBase(options, file), options);
2675                if (jsxImport) {
2676                    // synthesize `import "base/jsx-runtime"` declaration
2677                    (imports ||= []).push(createSyntheticImport(jsxImport, file));
2678                }
2679            }
2680
2681            for (const node of file.statements) {
2682                collectModuleReferences(node, /*inAmbientModule*/ false);
2683            }
2684            if ((file.flags & NodeFlags.PossiblyContainsDynamicImport) || isJavaScriptFile) {
2685                collectDynamicImportOrRequireCalls(file);
2686            }
2687
2688            file.imports = imports || emptyArray;
2689            file.moduleAugmentations = moduleAugmentations || emptyArray;
2690            file.ambientModuleNames = ambientModules || emptyArray;
2691
2692            return;
2693
2694            function collectModuleReferences(node: Statement, inAmbientModule: boolean): void {
2695                if (isAnyImportOrReExport(node)) {
2696                    const moduleNameExpr = getExternalModuleName(node);
2697                    // TypeScript 1.0 spec (April 2014): 12.1.6
2698                    // An ExternalImportDeclaration in an AmbientExternalModuleDeclaration may reference other external modules
2699                    // only through top - level external module names. Relative external module names are not permitted.
2700                    if (moduleNameExpr && isStringLiteral(moduleNameExpr) && moduleNameExpr.text && (!inAmbientModule || !isExternalModuleNameRelative(moduleNameExpr.text))) {
2701                        setParentRecursive(node, /*incremental*/ false); // we need parent data on imports before the program is fully bound, so we ensure it's set here
2702                        imports = append(imports, moduleNameExpr);
2703                        if (!usesUriStyleNodeCoreModules && currentNodeModulesDepth === 0 && !file.isDeclarationFile) {
2704                            usesUriStyleNodeCoreModules = startsWith(moduleNameExpr.text, "node:");
2705                        }
2706                    }
2707                }
2708                else if (isModuleDeclaration(node)) {
2709                    if (isAmbientModule(node) && (inAmbientModule || hasSyntacticModifier(node, ModifierFlags.Ambient) || file.isDeclarationFile)) {
2710                        (node.name as Mutable<Node>).parent = node;
2711                        const nameText = getTextOfIdentifierOrLiteral(node.name);
2712                        // Ambient module declarations can be interpreted as augmentations for some existing external modules.
2713                        // This will happen in two cases:
2714                        // - if current file is external module then module augmentation is a ambient module declaration defined in the top level scope
2715                        // - if current file is not external module then module augmentation is an ambient module declaration with non-relative module name
2716                        //   immediately nested in top level ambient module declaration .
2717                        if (isExternalModuleFile || (inAmbientModule && !isExternalModuleNameRelative(nameText))) {
2718                            (moduleAugmentations || (moduleAugmentations = [])).push(node.name);
2719                        }
2720                        else if (!inAmbientModule) {
2721                            if (file.isDeclarationFile) {
2722                                // for global .d.ts files record name of ambient module
2723                                (ambientModules || (ambientModules = [])).push(nameText);
2724                            }
2725                            // An AmbientExternalModuleDeclaration declares an external module.
2726                            // This type of declaration is permitted only in the global module.
2727                            // The StringLiteral must specify a top - level external module name.
2728                            // Relative external module names are not permitted
2729
2730                            // NOTE: body of ambient module is always a module block, if it exists
2731                            const body = (node as ModuleDeclaration).body as ModuleBlock;
2732                            if (body) {
2733                                for (const statement of body.statements) {
2734                                    collectModuleReferences(statement, /*inAmbientModule*/ true);
2735                                }
2736                            }
2737                        }
2738                    }
2739                }
2740            }
2741
2742            function collectDynamicImportOrRequireCalls(file: SourceFile) {
2743                const r = /import|require/g;
2744                while (r.exec(file.text) !== null) { // eslint-disable-line no-null/no-null
2745                    const node = getNodeAtPosition(file, r.lastIndex);
2746                    if (isJavaScriptFile && isRequireCall(node, /*checkArgumentIsStringLiteralLike*/ true)) {
2747                        setParentRecursive(node, /*incremental*/ false); // we need parent data on imports before the program is fully bound, so we ensure it's set here
2748                        imports = append(imports, node.arguments[0]);
2749                    }
2750                    // we have to check the argument list has length of at least 1. We will still have to process these even though we have parsing error.
2751                    else if (isImportCall(node) && node.arguments.length >= 1 && isStringLiteralLike(node.arguments[0])) {
2752                        setParentRecursive(node, /*incremental*/ false); // we need parent data on imports before the program is fully bound, so we ensure it's set here
2753                        imports = append(imports, node.arguments[0]);
2754                    }
2755                    else if (isLiteralImportTypeNode(node)) {
2756                        setParentRecursive(node, /*incremental*/ false); // we need parent data on imports before the program is fully bound, so we ensure it's set here
2757                        imports = append(imports, node.argument.literal);
2758                    }
2759                }
2760            }
2761
2762            /** Returns a token if position is in [start-of-leading-trivia, end), includes JSDoc only in JS files */
2763            function getNodeAtPosition(sourceFile: SourceFile, position: number): Node {
2764                let current: Node = sourceFile;
2765                const getContainingChild = (child: Node) => {
2766                    if (child.pos <= position && (position < child.end || (position === child.end && (child.kind === SyntaxKind.EndOfFileToken)))) {
2767                        return child;
2768                    }
2769                };
2770                while (true) {
2771                    const child = isJavaScriptFile && hasJSDocNodes(current) && forEach(current.jsDoc, getContainingChild) || forEachChild(current, getContainingChild);
2772                    if (!child) {
2773                        return current;
2774                    }
2775                    current = child;
2776                }
2777            }
2778        }
2779
2780        function getLibFileFromReference(ref: FileReference) {
2781            const libName = toFileNameLowerCase(ref.fileName);
2782            const libFileName = libMap.get(libName);
2783            if (libFileName) {
2784                return getSourceFile(pathForLibFile(libFileName));
2785            }
2786        }
2787
2788        /** This should have similar behavior to 'processSourceFile' without diagnostics or mutation. */
2789        function getSourceFileFromReference(referencingFile: SourceFile | UnparsedSource, ref: FileReference): SourceFile | undefined {
2790            return getSourceFileFromReferenceWorker(resolveTripleslashReference(ref.fileName, referencingFile.fileName), getSourceFile);
2791        }
2792
2793        function getSourceFileFromReferenceWorker(
2794            fileName: string,
2795            getSourceFile: (fileName: string) => SourceFile | undefined,
2796            fail?: (diagnostic: DiagnosticMessage, ...argument: string[]) => void,
2797            reason?: FileIncludeReason): SourceFile | undefined {
2798
2799            if (hasExtension(fileName)) {
2800                const canonicalFileName = host.getCanonicalFileName(fileName);
2801                if (!options.allowNonTsExtensions && !forEach(flatten(supportedExtensionsWithJsonIfResolveJsonModule), extension => fileExtensionIs(canonicalFileName, extension)) && !fileExtensionIs(canonicalFileName, Extension.Ets)) {
2802                    if (fail) {
2803                        if (hasJSFileExtension(canonicalFileName)) {
2804                            fail(Diagnostics.File_0_is_a_JavaScript_file_Did_you_mean_to_enable_the_allowJs_option, fileName);
2805                        }
2806                        else {
2807                            fail(Diagnostics.File_0_has_an_unsupported_extension_The_only_supported_extensions_are_1, fileName, "'" + flatten(supportedExtensions).join("', '") + "'");
2808                        }
2809                    }
2810                    return undefined;
2811                }
2812
2813                const sourceFile = getSourceFile(fileName);
2814                if (fail) {
2815                    if (!sourceFile) {
2816                        const redirect = getProjectReferenceRedirect(fileName);
2817                        if (redirect) {
2818                            fail(Diagnostics.Output_file_0_has_not_been_built_from_source_file_1, redirect, fileName);
2819                        }
2820                        else {
2821                            fail(Diagnostics.File_0_not_found, fileName);
2822                        }
2823                    }
2824                    else if (isReferencedFile(reason) && canonicalFileName === host.getCanonicalFileName(getSourceFileByPath(reason.file)!.fileName)) {
2825                        fail(Diagnostics.A_file_cannot_have_a_reference_to_itself);
2826                    }
2827                }
2828                return sourceFile;
2829            }
2830            else {
2831                const sourceFileNoExtension = options.allowNonTsExtensions && getSourceFile(fileName);
2832                if (sourceFileNoExtension) return sourceFileNoExtension;
2833
2834                if (fail && options.allowNonTsExtensions) {
2835                    fail(Diagnostics.File_0_not_found, fileName);
2836                    return undefined;
2837                }
2838
2839                // Only try adding extensions from the first supported group (which should be .ts/.tsx/.d.ts)
2840                const sourceFileWithAddedExtension = forEach(supportedExtensions[0], extension => getSourceFile(fileName + extension));
2841                if (fail && !sourceFileWithAddedExtension) fail(Diagnostics.Could_not_resolve_the_path_0_with_the_extensions_Colon_1, fileName, "'" + flatten(supportedExtensions).join("', '") + "'");
2842                return sourceFileWithAddedExtension;
2843            }
2844        }
2845
2846        /** This has side effects through `findSourceFile`. */
2847        function processSourceFile(fileName: string, isDefaultLib: boolean, ignoreNoDefaultLib: boolean, packageId: PackageId | undefined, reason: FileIncludeReason): void {
2848            getSourceFileFromReferenceWorker(
2849                fileName,
2850                fileName => findSourceFile(fileName, isDefaultLib, ignoreNoDefaultLib, reason, packageId), // TODO: GH#18217
2851                (diagnostic, ...args) => addFilePreprocessingFileExplainingDiagnostic(/*file*/ undefined, reason, diagnostic, args),
2852                reason
2853            );
2854        }
2855
2856        function processProjectReferenceFile(fileName: string, reason: ProjectReferenceFile) {
2857            return processSourceFile(fileName, /*isDefaultLib*/ false, /*ignoreNoDefaultLib*/ false, /*packageId*/ undefined, reason);
2858        }
2859
2860        function reportFileNamesDifferOnlyInCasingError(fileName: string, existingFile: SourceFile, reason: FileIncludeReason): void {
2861            const hasExistingReasonToReportErrorOn = !isReferencedFile(reason) && some(fileReasons.get(existingFile.path), isReferencedFile);
2862            if (hasExistingReasonToReportErrorOn) {
2863                addFilePreprocessingFileExplainingDiagnostic(existingFile, reason, Diagnostics.Already_included_file_name_0_differs_from_file_name_1_only_in_casing, [existingFile.fileName, fileName]);
2864            }
2865            else {
2866                addFilePreprocessingFileExplainingDiagnostic(existingFile, reason, Diagnostics.File_name_0_differs_from_already_included_file_name_1_only_in_casing, [fileName, existingFile.fileName]);
2867            }
2868        }
2869
2870        function createRedirectSourceFile(redirectTarget: SourceFile, unredirected: SourceFile, fileName: string, path: Path, resolvedPath: Path, originalFileName: string, sourceFileOptions: CreateSourceFileOptions): SourceFile {
2871            const redirect: SourceFile = Object.create(redirectTarget);
2872            redirect.fileName = fileName;
2873            redirect.path = path;
2874            redirect.resolvedPath = resolvedPath;
2875            redirect.originalFileName = originalFileName;
2876            redirect.redirectInfo = { redirectTarget, unredirected };
2877            redirect.packageJsonLocations = sourceFileOptions.packageJsonLocations?.length ? sourceFileOptions.packageJsonLocations : undefined;
2878            redirect.packageJsonScope = sourceFileOptions.packageJsonScope;
2879            sourceFilesFoundSearchingNodeModules.set(path, currentNodeModulesDepth > 0);
2880            Object.defineProperties(redirect, {
2881                id: {
2882                    get(this: SourceFile) { return this.redirectInfo!.redirectTarget.id; },
2883                    set(this: SourceFile, value: SourceFile["id"]) { this.redirectInfo!.redirectTarget.id = value; },
2884                },
2885                symbol: {
2886                    get(this: SourceFile) { return this.redirectInfo!.redirectTarget.symbol; },
2887                    set(this: SourceFile, value: SourceFile["symbol"]) { this.redirectInfo!.redirectTarget.symbol = value; },
2888                },
2889            });
2890            return redirect;
2891        }
2892
2893        // Get source file from normalized fileName
2894        function findSourceFile(fileName: string, isDefaultLib: boolean, ignoreNoDefaultLib: boolean, reason: FileIncludeReason, packageId: PackageId | undefined): SourceFile | undefined {
2895            tracing?.push(tracing.Phase.Program, "findSourceFile", {
2896                fileName,
2897                isDefaultLib: isDefaultLib || undefined,
2898                fileIncludeKind: (FileIncludeKind as any)[reason.kind],
2899            });
2900            const result = findSourceFileWorker(fileName, isDefaultLib, ignoreNoDefaultLib, reason, packageId);
2901            tracing?.pop();
2902            return result;
2903        }
2904
2905        function getCreateSourceFileOptions(fileName: string, moduleResolutionCache: ModuleResolutionCache | undefined, host: CompilerHost, options: CompilerOptions): CreateSourceFileOptions {
2906            // It's a _little odd_ that we can't set `impliedNodeFormat` until the program step - but it's the first and only time we have a resolution cache
2907            // and a freshly made source file node on hand at the same time, and we need both to set the field. Persisting the resolution cache all the way
2908            // to the check and emit steps would be bad - so we much prefer detecting and storing the format information on the source file node upfront.
2909            const result = getImpliedNodeFormatForFileWorker(getNormalizedAbsolutePath(fileName, currentDirectory), moduleResolutionCache?.getPackageJsonInfoCache(), host, options);
2910            const languageVersion = getEmitScriptTarget(options);
2911            const setExternalModuleIndicator = getSetExternalModuleIndicator(options);
2912            return typeof result === "object" ?
2913                { ...result, languageVersion, setExternalModuleIndicator } :
2914                { languageVersion, impliedNodeFormat: result, setExternalModuleIndicator };
2915        }
2916
2917        function findSourceFileWorker(fileName: string, isDefaultLib: boolean, ignoreNoDefaultLib: boolean, reason: FileIncludeReason, packageId: PackageId | undefined): SourceFile | undefined {
2918            const path = toPath(fileName);
2919            if (useSourceOfProjectReferenceRedirect) {
2920                let source = getSourceOfProjectReferenceRedirect(path);
2921                // If preserveSymlinks is true, module resolution wont jump the symlink
2922                // but the resolved real path may be the .d.ts from project reference
2923                // Note:: Currently we try the real path only if the
2924                // file is from node_modules or oh_modules to avoid having to run real path on all file paths
2925                const modulesPathPart: string = getModulePathPartByPMType(options.packageManagerType);
2926                if (!source &&
2927                    host.realpath &&
2928                    options.preserveSymlinks &&
2929                    isDeclarationFileName(fileName) &&
2930                    stringContains(fileName, modulesPathPart)) {
2931                    const realPath = toPath(host.realpath(fileName));
2932                    if (realPath !== path) source = getSourceOfProjectReferenceRedirect(realPath);
2933                }
2934                if (source) {
2935                    const file = isString(source) ?
2936                        findSourceFile(source, isDefaultLib, ignoreNoDefaultLib, reason, packageId) :
2937                        undefined;
2938                    if (file) addFileToFilesByName(file, path, /*redirectedPath*/ undefined);
2939                    return file;
2940                }
2941            }
2942            const originalFileName = fileName;
2943            if (filesByName.has(path)) {
2944                const file = filesByName.get(path);
2945                addFileIncludeReason(file || undefined, reason);
2946                // try to check if we've already seen this file but with a different casing in path
2947                // NOTE: this only makes sense for case-insensitive file systems, and only on files which are not redirected
2948                if (file && options.forceConsistentCasingInFileNames) {
2949                    const checkedName = file.fileName;
2950                    const isRedirect = toPath(checkedName) !== toPath(fileName);
2951                    if (isRedirect) {
2952                        fileName = getProjectReferenceRedirect(fileName) || fileName;
2953                    }
2954                    // Check if it differs only in drive letters its ok to ignore that error:
2955                    const checkedAbsolutePath = getNormalizedAbsolutePathWithoutRoot(checkedName, currentDirectory);
2956                    const inputAbsolutePath = getNormalizedAbsolutePathWithoutRoot(fileName, currentDirectory);
2957                    if (checkedAbsolutePath !== inputAbsolutePath) {
2958                        reportFileNamesDifferOnlyInCasingError(fileName, file, reason);
2959                    }
2960                }
2961
2962                // If the file was previously found via a node_modules or oh_modules search, but is now being processed as a root file,
2963                // then everything it sucks in may also be marked incorrectly, and needs to be checked again.
2964                if (file && sourceFilesFoundSearchingNodeModules.get(file.path) && currentNodeModulesDepth === 0) {
2965                    sourceFilesFoundSearchingNodeModules.set(file.path, false);
2966                    if (!options.noResolve) {
2967                        processReferencedFiles(file, isDefaultLib);
2968                        processTypeReferenceDirectives(file);
2969                    }
2970                    if (!options.noLib) {
2971                        processLibReferenceDirectives(file);
2972                    }
2973
2974                    modulesWithElidedImports.set(file.path, false);
2975                    processImportedModules(file);
2976                }
2977                // See if we need to reprocess the imports due to prior skipped imports
2978                else if (file && modulesWithElidedImports.get(file.path)) {
2979                    if (currentNodeModulesDepth < maxNodeModuleJsDepth) {
2980                        modulesWithElidedImports.set(file.path, false);
2981                        processImportedModules(file);
2982                    }
2983                }
2984
2985                return file || undefined;
2986            }
2987
2988            let redirectedPath: Path | undefined;
2989            if (isReferencedFile(reason) && !useSourceOfProjectReferenceRedirect) {
2990                const redirectProject = getProjectReferenceRedirectProject(fileName);
2991                if (redirectProject) {
2992                    if (outFile(redirectProject.commandLine.options)) {
2993                        // Shouldnt create many to 1 mapping file in --out scenario
2994                        return undefined;
2995                    }
2996                    const redirect = getProjectReferenceOutputName(redirectProject, fileName);
2997                    fileName = redirect;
2998                    // Once we start redirecting to a file, we can potentially come back to it
2999                    // via a back-reference from another file in the .d.ts folder. If that happens we'll
3000                    // end up trying to add it to the program *again* because we were tracking it via its
3001                    // original (un-redirected) name. So we have to map both the original path and the redirected path
3002                    // to the source file we're about to find/create
3003                    redirectedPath = toPath(redirect);
3004                }
3005            }
3006
3007            // We haven't looked for this file, do so now and cache result
3008            const sourceFileOptions = getCreateSourceFileOptions(fileName, moduleResolutionCache, host, options);
3009            const file = host.getSourceFile(
3010                fileName,
3011                sourceFileOptions,
3012                hostErrorMessage => addFilePreprocessingFileExplainingDiagnostic(/*file*/ undefined, reason, Diagnostics.Cannot_read_file_0_Colon_1, [fileName, hostErrorMessage]),
3013                shouldCreateNewSourceFile || (oldProgram?.getSourceFileByPath(toPath(fileName))?.impliedNodeFormat !== sourceFileOptions.impliedNodeFormat)
3014            );
3015
3016            if (packageId) {
3017                const packageIdKey = packageIdToString(packageId);
3018                const fileFromPackageId = packageIdToSourceFile.get(packageIdKey);
3019                if (fileFromPackageId) {
3020                    // Some other SourceFile already exists with this package name and version.
3021                    // Instead of creating a duplicate, just redirect to the existing one.
3022                    const dupFile = createRedirectSourceFile(fileFromPackageId, file!, fileName, path, toPath(fileName), originalFileName, sourceFileOptions);
3023                    redirectTargetsMap.add(fileFromPackageId.path, fileName);
3024                    addFileToFilesByName(dupFile, path, redirectedPath);
3025                    addFileIncludeReason(dupFile, reason);
3026                    sourceFileToPackageName.set(path, packageIdToPackageName(packageId));
3027                    processingOtherFiles!.push(dupFile);
3028                    return dupFile;
3029                }
3030                else if (file) {
3031                    // This is the first source file to have this packageId.
3032                    packageIdToSourceFile.set(packageIdKey, file);
3033                    sourceFileToPackageName.set(path, packageIdToPackageName(packageId));
3034                }
3035            }
3036            addFileToFilesByName(file, path, redirectedPath);
3037
3038            if (file) {
3039                sourceFilesFoundSearchingNodeModules.set(path, currentNodeModulesDepth > 0);
3040                file.fileName = fileName; // Ensure that source file has same name as what we were looking for
3041                file.path = path;
3042                file.resolvedPath = toPath(fileName);
3043                file.originalFileName = originalFileName;
3044                file.packageJsonLocations = sourceFileOptions.packageJsonLocations?.length ? sourceFileOptions.packageJsonLocations : undefined;
3045                file.packageJsonScope = sourceFileOptions.packageJsonScope;
3046                addFileIncludeReason(file, reason);
3047
3048                if (host.useCaseSensitiveFileNames()) {
3049                    const pathLowerCase = toFileNameLowerCase(path);
3050                    // for case-sensitive file systems check if we've already seen some file with similar filename ignoring case
3051                    const existingFile = filesByNameIgnoreCase!.get(pathLowerCase);
3052                    if (existingFile) {
3053                        reportFileNamesDifferOnlyInCasingError(fileName, existingFile, reason);
3054                    }
3055                    else {
3056                        filesByNameIgnoreCase!.set(pathLowerCase, file);
3057                    }
3058                }
3059
3060                skipDefaultLib = skipDefaultLib || (file.hasNoDefaultLib && !ignoreNoDefaultLib);
3061
3062                if (!options.noResolve) {
3063                    processReferencedFiles(file, isDefaultLib);
3064                    processTypeReferenceDirectives(file);
3065                }
3066                if (!options.noLib) {
3067                    processLibReferenceDirectives(file);
3068                }
3069
3070
3071                // always process imported modules to record module name resolutions
3072                processImportedModules(file);
3073
3074                if (isDefaultLib) {
3075                    processingDefaultLibFiles!.push(file);
3076                }
3077                else {
3078                    processingOtherFiles!.push(file);
3079                }
3080            }
3081            return file;
3082        }
3083
3084        function addFileIncludeReason(file: SourceFile | undefined, reason: FileIncludeReason) {
3085            if (file) fileReasons.add(file.path, reason);
3086        }
3087
3088        function addFileToFilesByName(file: SourceFile | undefined, path: Path, redirectedPath: Path | undefined) {
3089            if (redirectedPath) {
3090                filesByName.set(redirectedPath, file);
3091                filesByName.set(path, file || false);
3092            }
3093            else {
3094                filesByName.set(path, file);
3095            }
3096        }
3097
3098        function getProjectReferenceRedirect(fileName: string): string | undefined {
3099            const referencedProject = getProjectReferenceRedirectProject(fileName);
3100            return referencedProject && getProjectReferenceOutputName(referencedProject, fileName);
3101        }
3102
3103        function getProjectReferenceRedirectProject(fileName: string) {
3104            // Ignore dts or any json files
3105            if (!resolvedProjectReferences || !resolvedProjectReferences.length || isDeclarationFileName(fileName) || fileExtensionIs(fileName, Extension.Json)) {
3106                return undefined;
3107            }
3108
3109            // If this file is produced by a referenced project, we need to rewrite it to
3110            // look in the output folder of the referenced project rather than the input
3111            return getResolvedProjectReferenceToRedirect(fileName);
3112        }
3113
3114
3115        function getProjectReferenceOutputName(referencedProject: ResolvedProjectReference, fileName: string) {
3116            const out = outFile(referencedProject.commandLine.options);
3117            return out ?
3118                changeExtension(out, Extension.Dts) :
3119                getOutputDeclarationFileName(fileName, referencedProject.commandLine, !host.useCaseSensitiveFileNames());
3120        }
3121
3122        /**
3123         * Get the referenced project if the file is input file from that reference project
3124         */
3125        function getResolvedProjectReferenceToRedirect(fileName: string) {
3126            if (mapFromFileToProjectReferenceRedirects === undefined) {
3127                mapFromFileToProjectReferenceRedirects = new Map();
3128                forEachResolvedProjectReference(referencedProject => {
3129                    // not input file from the referenced project, ignore
3130                    if (toPath(options.configFilePath!) !== referencedProject.sourceFile.path) {
3131                        referencedProject.commandLine.fileNames.forEach(f =>
3132                            mapFromFileToProjectReferenceRedirects!.set(toPath(f), referencedProject.sourceFile.path));
3133                    }
3134                });
3135            }
3136
3137            const referencedProjectPath = mapFromFileToProjectReferenceRedirects.get(toPath(fileName));
3138            return referencedProjectPath && getResolvedProjectReferenceByPath(referencedProjectPath);
3139        }
3140
3141        function forEachResolvedProjectReference<T>(
3142            cb: (resolvedProjectReference: ResolvedProjectReference) => T | undefined
3143        ): T | undefined {
3144            return ts.forEachResolvedProjectReference(resolvedProjectReferences, cb);
3145        }
3146
3147        function getSourceOfProjectReferenceRedirect(path: Path) {
3148            if (!isDeclarationFileName(path)) return undefined;
3149            if (mapFromToProjectReferenceRedirectSource === undefined) {
3150                mapFromToProjectReferenceRedirectSource = new Map();
3151                forEachResolvedProjectReference(resolvedRef => {
3152                    const out = outFile(resolvedRef.commandLine.options);
3153                    if (out) {
3154                        // Dont know which source file it means so return true?
3155                        const outputDts = changeExtension(out, Extension.Dts);
3156                        mapFromToProjectReferenceRedirectSource!.set(toPath(outputDts), true);
3157                    }
3158                    else {
3159                        const getCommonSourceDirectory = memoize(() => getCommonSourceDirectoryOfConfig(resolvedRef.commandLine, !host.useCaseSensitiveFileNames()));
3160                        forEach(resolvedRef.commandLine.fileNames, fileName => {
3161                            if (!isDeclarationFileName(fileName) && !fileExtensionIs(fileName, Extension.Json)) {
3162                                const outputDts = getOutputDeclarationFileName(fileName, resolvedRef.commandLine, !host.useCaseSensitiveFileNames(), getCommonSourceDirectory);
3163                                mapFromToProjectReferenceRedirectSource!.set(toPath(outputDts), fileName);
3164                            }
3165                        });
3166                    }
3167                });
3168            }
3169            return mapFromToProjectReferenceRedirectSource.get(path);
3170        }
3171
3172        function isSourceOfProjectReferenceRedirect(fileName: string) {
3173            return useSourceOfProjectReferenceRedirect && !!getResolvedProjectReferenceToRedirect(fileName);
3174        }
3175
3176        function getResolvedProjectReferenceByPath(projectReferencePath: Path): ResolvedProjectReference | undefined {
3177            if (!projectReferenceRedirects) {
3178                return undefined;
3179            }
3180
3181            return projectReferenceRedirects.get(projectReferencePath) || undefined;
3182        }
3183
3184        function processReferencedFiles(file: SourceFile, isDefaultLib: boolean) {
3185            forEach(file.referencedFiles, (ref, index) => {
3186                processSourceFile(
3187                    resolveTripleslashReference(ref.fileName, file.fileName),
3188                    isDefaultLib,
3189                    /*ignoreNoDefaultLib*/ false,
3190                    /*packageId*/ undefined,
3191                    { kind: FileIncludeKind.ReferenceFile, file: file.path, index, }
3192                );
3193            });
3194        }
3195
3196        function processTypeReferenceDirectives(file: SourceFile) {
3197            const typeDirectives = file.typeReferenceDirectives;
3198            if (!typeDirectives) {
3199                return;
3200            }
3201
3202            const resolutions = resolveTypeReferenceDirectiveNamesWorker(typeDirectives, file);
3203            for (let index = 0; index < typeDirectives.length; index++) {
3204                const ref = file.typeReferenceDirectives[index];
3205                const resolvedTypeReferenceDirective = resolutions[index];
3206                // store resolved type directive on the file
3207                const fileName = toFileNameLowerCase(ref.fileName);
3208                setResolvedTypeReferenceDirective(file, fileName, resolvedTypeReferenceDirective);
3209                const mode = ref.resolutionMode || file.impliedNodeFormat;
3210                if (mode && getEmitModuleResolutionKind(options) !== ModuleResolutionKind.Node16 && getEmitModuleResolutionKind(options) !== ModuleResolutionKind.NodeNext) {
3211                    programDiagnostics.add(createDiagnosticForRange(file, ref, Diagnostics.resolution_mode_assertions_are_only_supported_when_moduleResolution_is_node16_or_nodenext));
3212                }
3213                processTypeReferenceDirective(fileName, mode, resolvedTypeReferenceDirective, { kind: FileIncludeKind.TypeReferenceDirective, file: file.path, index, });
3214            }
3215        }
3216
3217        function processTypeReferenceDirective(
3218            typeReferenceDirective: string,
3219            mode: SourceFile["impliedNodeFormat"] | undefined,
3220            resolvedTypeReferenceDirective: ResolvedTypeReferenceDirective | undefined,
3221            reason: FileIncludeReason
3222        ): void {
3223            tracing?.push(tracing.Phase.Program, "processTypeReferenceDirective", { directive: typeReferenceDirective, hasResolved: !!resolvedTypeReferenceDirective, refKind: reason.kind, refPath: isReferencedFile(reason) ? reason.file : undefined });
3224            processTypeReferenceDirectiveWorker(typeReferenceDirective, mode, resolvedTypeReferenceDirective, reason);
3225            tracing?.pop();
3226        }
3227
3228        function processTypeReferenceDirectiveWorker(
3229            typeReferenceDirective: string,
3230            mode: SourceFile["impliedNodeFormat"] | undefined,
3231            resolvedTypeReferenceDirective: ResolvedTypeReferenceDirective | undefined,
3232            reason: FileIncludeReason
3233        ): void {
3234
3235            // If we already found this library as a primary reference - nothing to do
3236            const previousResolution = resolvedTypeReferenceDirectives.get(typeReferenceDirective, mode);
3237            if (previousResolution && previousResolution.primary) {
3238                return;
3239            }
3240            let saveResolution = true;
3241            if (resolvedTypeReferenceDirective) {
3242                if (resolvedTypeReferenceDirective.isExternalLibraryImport) currentNodeModulesDepth++;
3243
3244                if (resolvedTypeReferenceDirective.primary) {
3245                    // resolved from the primary path
3246                    processSourceFile(resolvedTypeReferenceDirective.resolvedFileName!, /*isDefaultLib*/ false, /*ignoreNoDefaultLib*/ false, resolvedTypeReferenceDirective.packageId, reason); // TODO: GH#18217
3247                }
3248                else {
3249                    // If we already resolved to this file, it must have been a secondary reference. Check file contents
3250                    // for sameness and possibly issue an error
3251                    if (previousResolution) {
3252                        // Don't bother reading the file again if it's the same file.
3253                        if (resolvedTypeReferenceDirective.resolvedFileName !== previousResolution.resolvedFileName) {
3254                            const otherFileText = host.readFile(resolvedTypeReferenceDirective.resolvedFileName!);
3255                            const existingFile = getSourceFile(previousResolution.resolvedFileName!)!;
3256                            if (otherFileText !== existingFile.text) {
3257                                addFilePreprocessingFileExplainingDiagnostic(
3258                                    existingFile,
3259                                    reason,
3260                                    Diagnostics.Conflicting_definitions_for_0_found_at_1_and_2_Consider_installing_a_specific_version_of_this_library_to_resolve_the_conflict,
3261                                    [typeReferenceDirective, resolvedTypeReferenceDirective.resolvedFileName, previousResolution.resolvedFileName]
3262                                );
3263                            }
3264                        }
3265                        // don't overwrite previous resolution result
3266                        saveResolution = false;
3267                    }
3268                    else {
3269                        // First resolution of this library
3270                        processSourceFile(resolvedTypeReferenceDirective.resolvedFileName!, /*isDefaultLib*/ false, /*ignoreNoDefaultLib*/ false, resolvedTypeReferenceDirective.packageId, reason);
3271                    }
3272                }
3273
3274                if (resolvedTypeReferenceDirective.isExternalLibraryImport) currentNodeModulesDepth--;
3275            }
3276            else {
3277                addFilePreprocessingFileExplainingDiagnostic(/*file*/ undefined, reason, Diagnostics.Cannot_find_type_definition_file_for_0, [typeReferenceDirective]);
3278            }
3279
3280            if (saveResolution) {
3281                resolvedTypeReferenceDirectives.set(typeReferenceDirective, mode, resolvedTypeReferenceDirective);
3282            }
3283        }
3284
3285        function pathForLibFile(libFileName: string): string {
3286            // Support resolving to lib.dom.d.ts -> @typescript/lib-dom, and
3287            //                      lib.dom.iterable.d.ts -> @typescript/lib-dom/iterable
3288            //                      lib.es2015.symbol.wellknown.d.ts -> @typescript/lib-es2015/symbol-wellknown
3289            const components = libFileName.split(".");
3290            let path = components[1];
3291            let i = 2;
3292            while (components[i] && components[i] !== "d") {
3293                path += (i === 2 ? "/" : "-") + components[i];
3294                i++;
3295            }
3296            const modulePathType = getModuleByPMType(options.packageManagerType);
3297            const resolveFrom = combinePaths(currentDirectory, `__lib_${modulePathType}_lookup_${libFileName}__.ts`);
3298            const localOverrideModuleResult = resolveModuleName("@typescript/lib-" + path, resolveFrom, { moduleResolution: ModuleResolutionKind.NodeJs }, host, moduleResolutionCache);
3299            if (localOverrideModuleResult?.resolvedModule) {
3300                return localOverrideModuleResult.resolvedModule.resolvedFileName;
3301            }
3302            return combinePaths(defaultLibraryPath, libFileName);
3303        }
3304
3305        function processLibReferenceDirectives(file: SourceFile) {
3306            forEach(file.libReferenceDirectives, (libReference, index) => {
3307                const libName = toFileNameLowerCase(libReference.fileName);
3308                const libFileName = libMap.get(libName);
3309                if (libFileName) {
3310                    // we ignore any 'no-default-lib' reference set on this file.
3311                    processRootFile(pathForLibFile(libFileName), /*isDefaultLib*/ true, /*ignoreNoDefaultLib*/ true, { kind: FileIncludeKind.LibReferenceDirective, file: file.path, index, });
3312                }
3313                else {
3314                    const unqualifiedLibName = removeSuffix(removePrefix(libName, "lib."), ".d.ts");
3315                    const suggestion = getSpellingSuggestion(unqualifiedLibName, libs, identity);
3316                    const diagnostic = suggestion ? Diagnostics.Cannot_find_lib_definition_for_0_Did_you_mean_1 : Diagnostics.Cannot_find_lib_definition_for_0;
3317                    (fileProcessingDiagnostics ||= []).push({
3318                        kind: FilePreprocessingDiagnosticsKind.FilePreprocessingReferencedDiagnostic,
3319                        reason: { kind: FileIncludeKind.LibReferenceDirective, file: file.path, index, },
3320                        diagnostic,
3321                        args: [libName, suggestion]
3322                    });
3323                }
3324            });
3325        }
3326
3327        function getCanonicalFileName(fileName: string): string {
3328            return host.getCanonicalFileName(fileName);
3329        }
3330
3331        function processImportedModules(file: SourceFile) {
3332            collectExternalModuleReferences(file);
3333            if (file.imports.length || file.moduleAugmentations.length) {
3334                // Because global augmentation doesn't have string literal name, we can check for global augmentation as such.
3335                const moduleNames = getModuleNames(file);
3336                const resolutions = resolveModuleNamesReusingOldState(moduleNames, file);
3337                Debug.assert(resolutions.length === moduleNames.length);
3338                const optionsForFile = (useSourceOfProjectReferenceRedirect ? getRedirectReferenceForResolution(file)?.commandLine.options : undefined) || options;
3339                for (let index = 0; index < moduleNames.length; index++) {
3340                    const resolution = resolutions[index];
3341                    setResolvedModule(file, moduleNames[index], resolution, getModeForResolutionAtIndex(file, index));
3342
3343                    if (!resolution) {
3344                        continue;
3345                    }
3346
3347                    const isFromNodeModulesSearch = resolution.isExternalLibraryImport;
3348                    const isJsFile = !resolutionExtensionIsTSOrJson(resolution.extension);
3349                    const isJsFileFromNodeModules = isFromNodeModulesSearch && isJsFile;
3350                    const resolvedFileName = resolution.resolvedFileName;
3351
3352                    if (isFromNodeModulesSearch) {
3353                        currentNodeModulesDepth++;
3354                    }
3355
3356                    // add file to program only if:
3357                    // - resolution was successful
3358                    // - noResolve is falsy
3359                    // - module name comes from the list of imports
3360                    // - it's not a top level JavaScript module that exceeded the search max
3361                    const elideImport = isJsFileFromNodeModules && currentNodeModulesDepth > maxNodeModuleJsDepth;
3362                    // Don't add the file if it has a bad extension (e.g. 'tsx' if we don't have '--allowJs')
3363                    // This may still end up being an untyped module -- the file won't be included but imports will be allowed.
3364                    const shouldAddFile = resolvedFileName
3365                        && !getResolutionDiagnostic(optionsForFile, resolution)
3366                        && !optionsForFile.noResolve
3367                        && index < file.imports.length
3368                        && !elideImport
3369                        && !(isJsFile && !getAllowJSCompilerOption(optionsForFile))
3370                        && (isInJSFile(file.imports[index]) || !(file.imports[index].flags & NodeFlags.JSDoc));
3371
3372                    if (elideImport) {
3373                        modulesWithElidedImports.set(file.path, true);
3374                    }
3375                    else if (shouldAddFile) {
3376                        findSourceFile(
3377                            resolvedFileName,
3378                            /*isDefaultLib*/ false,
3379                            /*ignoreNoDefaultLib*/ false,
3380                            { kind: FileIncludeKind.Import, file: file.path, index, },
3381                            resolution.packageId,
3382                        );
3383                    }
3384
3385                    if (isFromNodeModulesSearch) {
3386                        currentNodeModulesDepth--;
3387                    }
3388                }
3389            }
3390            else {
3391                // no imports - drop cached module resolutions
3392                file.resolvedModules = undefined;
3393            }
3394        }
3395
3396        function checkSourceFilesBelongToPath(sourceFiles: readonly SourceFile[], rootDirectory: string): boolean {
3397            let allFilesBelongToPath = true;
3398            const absoluteRootDirectoryPath = host.getCanonicalFileName(getNormalizedAbsolutePath(rootDirectory, currentDirectory));
3399            for (const sourceFile of sourceFiles) {
3400                if (!sourceFile.isDeclarationFile) {
3401                    const absoluteSourceFilePath = host.getCanonicalFileName(getNormalizedAbsolutePath(sourceFile.fileName, currentDirectory));
3402                    if (absoluteSourceFilePath.indexOf(absoluteRootDirectoryPath) !== 0) {
3403                        addProgramDiagnosticExplainingFile(
3404                            sourceFile,
3405                            Diagnostics.File_0_is_not_under_rootDir_1_rootDir_is_expected_to_contain_all_source_files,
3406                            [sourceFile.fileName, rootDirectory]
3407                        );
3408                        allFilesBelongToPath = false;
3409                    }
3410                }
3411            }
3412
3413            return allFilesBelongToPath;
3414        }
3415
3416        function parseProjectReferenceConfigFile(ref: ProjectReference): ResolvedProjectReference | undefined {
3417            if (!projectReferenceRedirects) {
3418                projectReferenceRedirects = new Map();
3419            }
3420
3421            // The actual filename (i.e. add "/tsconfig.json" if necessary)
3422            const refPath = resolveProjectReferencePath(ref);
3423            const sourceFilePath = toPath(refPath);
3424            const fromCache = projectReferenceRedirects.get(sourceFilePath);
3425            if (fromCache !== undefined) {
3426                return fromCache || undefined;
3427            }
3428
3429            let commandLine: ParsedCommandLine | undefined;
3430            let sourceFile: JsonSourceFile | undefined;
3431            if (host.getParsedCommandLine) {
3432                commandLine = host.getParsedCommandLine(refPath);
3433                if (!commandLine) {
3434                    addFileToFilesByName(/*sourceFile*/ undefined, sourceFilePath, /*redirectedPath*/ undefined);
3435                    projectReferenceRedirects.set(sourceFilePath, false);
3436                    return undefined;
3437                }
3438                sourceFile = Debug.checkDefined(commandLine.options.configFile);
3439                Debug.assert(!sourceFile.path || sourceFile.path === sourceFilePath);
3440                addFileToFilesByName(sourceFile, sourceFilePath, /*redirectedPath*/ undefined);
3441            }
3442            else {
3443                // An absolute path pointing to the containing directory of the config file
3444                const basePath = getNormalizedAbsolutePath(getDirectoryPath(refPath), host.getCurrentDirectory());
3445                sourceFile = host.getSourceFile(refPath, ScriptTarget.JSON) as JsonSourceFile | undefined;
3446                addFileToFilesByName(sourceFile, sourceFilePath, /*redirectedPath*/ undefined);
3447                if (sourceFile === undefined) {
3448                    projectReferenceRedirects.set(sourceFilePath, false);
3449                    return undefined;
3450                }
3451                commandLine = parseJsonSourceFileConfigFileContent(sourceFile, configParsingHost, basePath, /*existingOptions*/ undefined, refPath);
3452            }
3453            sourceFile.fileName = refPath;
3454            sourceFile.path = sourceFilePath;
3455            sourceFile.resolvedPath = sourceFilePath;
3456            sourceFile.originalFileName = refPath;
3457
3458            const resolvedRef: ResolvedProjectReference = { commandLine, sourceFile };
3459            projectReferenceRedirects.set(sourceFilePath, resolvedRef);
3460            if (commandLine.projectReferences) {
3461                resolvedRef.references = commandLine.projectReferences.map(parseProjectReferenceConfigFile);
3462            }
3463            return resolvedRef;
3464        }
3465
3466        function verifyCompilerOptions() {
3467            if (options.strictPropertyInitialization && !getStrictOptionValue(options, "strictNullChecks")) {
3468                createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1, "strictPropertyInitialization", "strictNullChecks");
3469            }
3470            if (options.exactOptionalPropertyTypes && !getStrictOptionValue(options, "strictNullChecks")) {
3471                createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1, "exactOptionalPropertyTypes", "strictNullChecks");
3472            }
3473
3474            if (options.isolatedModules) {
3475                if (options.out) {
3476                    createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_with_option_1, "out", "isolatedModules");
3477                }
3478
3479                if (options.outFile) {
3480                    createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_with_option_1, "outFile", "isolatedModules");
3481                }
3482            }
3483
3484            if (options.inlineSourceMap) {
3485                if (options.sourceMap) {
3486                    createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_with_option_1, "sourceMap", "inlineSourceMap");
3487                }
3488                if (options.mapRoot) {
3489                    createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_with_option_1, "mapRoot", "inlineSourceMap");
3490                }
3491            }
3492
3493            if (options.composite) {
3494                if (options.declaration === false) {
3495                    createDiagnosticForOptionName(Diagnostics.Composite_projects_may_not_disable_declaration_emit, "declaration");
3496                }
3497                if (options.incremental === false) {
3498                    createDiagnosticForOptionName(Diagnostics.Composite_projects_may_not_disable_incremental_compilation, "declaration");
3499                }
3500            }
3501
3502            const outputFile = outFile(options);
3503            if (options.tsBuildInfoFile) {
3504                if (!isIncrementalCompilation(options)) {
3505                    createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1_or_option_2, "tsBuildInfoFile", "incremental", "composite");
3506                }
3507            }
3508            else if (options.incremental && !outputFile && !options.configFilePath) {
3509                programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Option_incremental_can_only_be_specified_using_tsconfig_emitting_to_single_file_or_when_option_tsBuildInfoFile_is_specified));
3510            }
3511
3512            verifyProjectReferences();
3513
3514            // List of collected files is complete; validate exhautiveness if this is a project with a file list
3515            if (options.composite) {
3516                const rootPaths = new Set(rootNames.map(toPath));
3517                for (const file of files) {
3518                    // Ignore file that is not emitted
3519                    if (sourceFileMayBeEmitted(file, program) && !rootPaths.has(file.path)) {
3520                        addProgramDiagnosticExplainingFile(
3521                            file,
3522                            Diagnostics.File_0_is_not_listed_within_the_file_list_of_project_1_Projects_must_list_all_files_or_use_an_include_pattern,
3523                            [file.fileName, options.configFilePath || ""]
3524                        );
3525                    }
3526                }
3527            }
3528
3529            if (options.paths) {
3530                for (const key in options.paths) {
3531                    if (!hasProperty(options.paths, key)) {
3532                        continue;
3533                    }
3534                    if (!hasZeroOrOneAsteriskCharacter(key)) {
3535                        createDiagnosticForOptionPaths(/*onKey*/ true, key, Diagnostics.Pattern_0_can_have_at_most_one_Asterisk_character, key);
3536                    }
3537                    if (isArray(options.paths[key])) {
3538                        const len = options.paths[key].length;
3539                        if (len === 0) {
3540                            createDiagnosticForOptionPaths(/*onKey*/ false, key, Diagnostics.Substitutions_for_pattern_0_shouldn_t_be_an_empty_array, key);
3541                        }
3542                        for (let i = 0; i < len; i++) {
3543                            const subst = options.paths[key][i];
3544                            const typeOfSubst = typeof subst;
3545                            if (typeOfSubst === "string") {
3546                                if (!hasZeroOrOneAsteriskCharacter(subst)) {
3547                                    createDiagnosticForOptionPathKeyValue(key, i, Diagnostics.Substitution_0_in_pattern_1_can_have_at_most_one_Asterisk_character, subst, key);
3548                                }
3549                                if (!options.baseUrl && !pathIsRelative(subst) && !pathIsAbsolute(subst)) {
3550                                    createDiagnosticForOptionPathKeyValue(key, i, Diagnostics.Non_relative_paths_are_not_allowed_when_baseUrl_is_not_set_Did_you_forget_a_leading_Slash);
3551                                }
3552                            }
3553                            else {
3554                                createDiagnosticForOptionPathKeyValue(key, i, Diagnostics.Substitution_0_for_pattern_1_has_incorrect_type_expected_string_got_2, subst, key, typeOfSubst);
3555                            }
3556                        }
3557                    }
3558                    else {
3559                        createDiagnosticForOptionPaths(/*onKey*/ false, key, Diagnostics.Substitutions_for_pattern_0_should_be_an_array, key);
3560                    }
3561                }
3562            }
3563
3564            if (!options.sourceMap && !options.inlineSourceMap) {
3565                if (options.inlineSources) {
3566                    createDiagnosticForOptionName(Diagnostics.Option_0_can_only_be_used_when_either_option_inlineSourceMap_or_option_sourceMap_is_provided, "inlineSources");
3567                }
3568                if (options.sourceRoot) {
3569                    createDiagnosticForOptionName(Diagnostics.Option_0_can_only_be_used_when_either_option_inlineSourceMap_or_option_sourceMap_is_provided, "sourceRoot");
3570                }
3571            }
3572
3573            if (options.out && options.outFile) {
3574                createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_with_option_1, "out", "outFile");
3575            }
3576
3577            if (options.mapRoot && !(options.sourceMap || options.declarationMap)) {
3578                // Error to specify --mapRoot without --sourcemap
3579                createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1_or_option_2, "mapRoot", "sourceMap", "declarationMap");
3580            }
3581
3582            if (options.declarationDir) {
3583                if (!getEmitDeclarations(options)) {
3584                    createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1_or_option_2, "declarationDir", "declaration", "composite");
3585                }
3586                if (outputFile) {
3587                    createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_with_option_1, "declarationDir", options.out ? "out" : "outFile");
3588                }
3589            }
3590
3591            if (options.declarationMap && !getEmitDeclarations(options)) {
3592                createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1_or_option_2, "declarationMap", "declaration", "composite");
3593            }
3594
3595            if (options.lib && options.noLib) {
3596                createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_with_option_1, "lib", "noLib");
3597            }
3598
3599            if (options.noImplicitUseStrict && getStrictOptionValue(options, "alwaysStrict")) {
3600                createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_with_option_1, "noImplicitUseStrict", "alwaysStrict");
3601            }
3602
3603            const languageVersion = getEmitScriptTarget(options);
3604
3605            const firstNonAmbientExternalModuleSourceFile = find(files, f => isExternalModule(f) && !f.isDeclarationFile);
3606            if (options.isolatedModules) {
3607                if (options.module === ModuleKind.None && languageVersion < ScriptTarget.ES2015) {
3608                    createDiagnosticForOptionName(Diagnostics.Option_isolatedModules_can_only_be_used_when_either_option_module_is_provided_or_option_target_is_ES2015_or_higher, "isolatedModules", "target");
3609                }
3610
3611                if (options.preserveConstEnums === false) {
3612                    createDiagnosticForOptionName(Diagnostics.Option_preserveConstEnums_cannot_be_disabled_when_isolatedModules_is_enabled, "preserveConstEnums", "isolatedModules");
3613                }
3614
3615                for (const file of files) {
3616                    if (!isExternalModule(file) && !isSourceFileJS(file) && !file.isDeclarationFile && file.scriptKind !== ScriptKind.JSON) {
3617                        const span = getErrorSpanForNode(file, file);
3618                        programDiagnostics.add(createFileDiagnostic(file, span.start, span.length,
3619                            Diagnostics._0_cannot_be_compiled_under_isolatedModules_because_it_is_considered_a_global_script_file_Add_an_import_export_or_an_empty_export_statement_to_make_it_a_module, getBaseFileName(file.fileName)));
3620                    }
3621                }
3622            }
3623            else if (firstNonAmbientExternalModuleSourceFile && languageVersion < ScriptTarget.ES2015 && options.module === ModuleKind.None) {
3624                // We cannot use createDiagnosticFromNode because nodes do not have parents yet
3625                const span = getErrorSpanForNode(firstNonAmbientExternalModuleSourceFile, typeof firstNonAmbientExternalModuleSourceFile.externalModuleIndicator === "boolean" ? firstNonAmbientExternalModuleSourceFile : firstNonAmbientExternalModuleSourceFile.externalModuleIndicator!);
3626                programDiagnostics.add(createFileDiagnostic(firstNonAmbientExternalModuleSourceFile, span.start, span.length, Diagnostics.Cannot_use_imports_exports_or_module_augmentations_when_module_is_none));
3627            }
3628
3629            // Cannot specify module gen that isn't amd or system with --out
3630            if (outputFile && !options.emitDeclarationOnly) {
3631                if (options.module && !(options.module === ModuleKind.AMD || options.module === ModuleKind.System)) {
3632                    createDiagnosticForOptionName(Diagnostics.Only_amd_and_system_modules_are_supported_alongside_0, options.out ? "out" : "outFile", "module");
3633                }
3634                else if (options.module === undefined && firstNonAmbientExternalModuleSourceFile) {
3635                    const span = getErrorSpanForNode(firstNonAmbientExternalModuleSourceFile, typeof firstNonAmbientExternalModuleSourceFile.externalModuleIndicator === "boolean" ? firstNonAmbientExternalModuleSourceFile : firstNonAmbientExternalModuleSourceFile.externalModuleIndicator!);
3636                    programDiagnostics.add(createFileDiagnostic(firstNonAmbientExternalModuleSourceFile, span.start, span.length, Diagnostics.Cannot_compile_modules_using_option_0_unless_the_module_flag_is_amd_or_system, options.out ? "out" : "outFile"));
3637                }
3638            }
3639
3640            if (options.resolveJsonModule) {
3641                if (getEmitModuleResolutionKind(options) !== ModuleResolutionKind.NodeJs &&
3642                    getEmitModuleResolutionKind(options) !== ModuleResolutionKind.Node16 &&
3643                    getEmitModuleResolutionKind(options) !== ModuleResolutionKind.NodeNext) {
3644                    createDiagnosticForOptionName(Diagnostics.Option_resolveJsonModule_cannot_be_specified_without_node_module_resolution_strategy, "resolveJsonModule");
3645                }
3646                // Any emit other than common js, amd, es2015 or esnext is error
3647                else if (!hasJsonModuleEmitEnabled(options)) {
3648                    createDiagnosticForOptionName(Diagnostics.Option_resolveJsonModule_can_only_be_specified_when_module_code_generation_is_commonjs_amd_es2015_or_esNext, "resolveJsonModule", "module");
3649                }
3650            }
3651
3652            // there has to be common source directory if user specified --outdir || --rootDir || --sourceRoot
3653            // if user specified --mapRoot, there needs to be common source directory if there would be multiple files being emitted
3654            if (options.outDir || // there is --outDir specified
3655                options.rootDir || // there is --rootDir specified
3656                options.sourceRoot || // there is --sourceRoot specified
3657                options.mapRoot) { // there is --mapRoot specified
3658
3659                // Precalculate and cache the common source directory
3660                const dir = getCommonSourceDirectory();
3661
3662                // If we failed to find a good common directory, but outDir is specified and at least one of our files is on a windows drive/URL/other resource, add a failure
3663                if (options.outDir && dir === "" && files.some(file => getRootLength(file.fileName) > 1)) {
3664                    createDiagnosticForOptionName(Diagnostics.Cannot_find_the_common_subdirectory_path_for_the_input_files, "outDir");
3665                }
3666            }
3667
3668            if (options.useDefineForClassFields && languageVersion === ScriptTarget.ES3) {
3669                createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_when_option_target_is_ES3, "useDefineForClassFields");
3670            }
3671
3672            if (options.checkJs && !getAllowJSCompilerOption(options)) {
3673                programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1, "checkJs", "allowJs"));
3674            }
3675
3676            if (options.emitDeclarationOnly) {
3677                if (!getEmitDeclarations(options)) {
3678                    createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1_or_option_2, "emitDeclarationOnly", "declaration", "composite");
3679                }
3680
3681                if (options.noEmit) {
3682                    createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_with_option_1, "emitDeclarationOnly", "noEmit");
3683                }
3684            }
3685
3686            if (options.emitDecoratorMetadata &&
3687                !options.experimentalDecorators) {
3688                createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1, "emitDecoratorMetadata", "experimentalDecorators");
3689            }
3690
3691            if (options.jsxFactory) {
3692                if (options.reactNamespace) {
3693                    createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_with_option_1, "reactNamespace", "jsxFactory");
3694                }
3695                if (options.jsx === JsxEmit.ReactJSX || options.jsx === JsxEmit.ReactJSXDev) {
3696                    createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_when_option_jsx_is_1, "jsxFactory", inverseJsxOptionMap.get("" + options.jsx));
3697                }
3698                if (!parseIsolatedEntityName(options.jsxFactory, languageVersion)) {
3699                    createOptionValueDiagnostic("jsxFactory", Diagnostics.Invalid_value_for_jsxFactory_0_is_not_a_valid_identifier_or_qualified_name, options.jsxFactory);
3700                }
3701            }
3702            else if (options.reactNamespace && !isIdentifierText(options.reactNamespace, languageVersion)) {
3703                createOptionValueDiagnostic("reactNamespace", Diagnostics.Invalid_value_for_reactNamespace_0_is_not_a_valid_identifier, options.reactNamespace);
3704            }
3705
3706            if (options.jsxFragmentFactory) {
3707                if (!options.jsxFactory) {
3708                    createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1, "jsxFragmentFactory", "jsxFactory");
3709                }
3710                if (options.jsx === JsxEmit.ReactJSX || options.jsx === JsxEmit.ReactJSXDev) {
3711                    createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_when_option_jsx_is_1, "jsxFragmentFactory", inverseJsxOptionMap.get("" + options.jsx));
3712                }
3713                if (!parseIsolatedEntityName(options.jsxFragmentFactory, languageVersion)) {
3714                    createOptionValueDiagnostic("jsxFragmentFactory", Diagnostics.Invalid_value_for_jsxFragmentFactory_0_is_not_a_valid_identifier_or_qualified_name, options.jsxFragmentFactory);
3715                }
3716            }
3717
3718            if (options.reactNamespace) {
3719                if (options.jsx === JsxEmit.ReactJSX || options.jsx === JsxEmit.ReactJSXDev) {
3720                    createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_when_option_jsx_is_1, "reactNamespace", inverseJsxOptionMap.get("" + options.jsx));
3721                }
3722            }
3723
3724            if (options.jsxImportSource) {
3725                if (options.jsx === JsxEmit.React) {
3726                    createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_when_option_jsx_is_1, "jsxImportSource", inverseJsxOptionMap.get("" + options.jsx));
3727                }
3728            }
3729
3730            if (options.preserveValueImports && getEmitModuleKind(options) < ModuleKind.ES2015) {
3731                createOptionValueDiagnostic("importsNotUsedAsValues", Diagnostics.Option_preserveValueImports_can_only_be_used_when_module_is_set_to_es2015_or_later);
3732            }
3733
3734            // If the emit is enabled make sure that every output file is unique and not overwriting any of the input files
3735            if (!options.noEmit && !options.suppressOutputPathCheck) {
3736                const emitHost = getEmitHost();
3737                const emitFilesSeen = new Set<string>();
3738                forEachEmittedFile(emitHost, (emitFileNames) => {
3739                    if (!options.emitDeclarationOnly) {
3740                        verifyEmitFilePath(emitFileNames.jsFilePath, emitFilesSeen);
3741                    }
3742                    verifyEmitFilePath(emitFileNames.declarationFilePath, emitFilesSeen);
3743                });
3744            }
3745
3746            // Verify that all the emit files are unique and don't overwrite input files
3747            function verifyEmitFilePath(emitFileName: string | undefined, emitFilesSeen: Set<string>) {
3748                if (emitFileName) {
3749                    const emitFilePath = toPath(emitFileName);
3750                    // Report error if the output overwrites input file
3751                    if (filesByName.has(emitFilePath)) {
3752                        let chain: DiagnosticMessageChain | undefined;
3753                        if (!options.configFilePath) {
3754                            // The program is from either an inferred project or an external project
3755                            chain = chainDiagnosticMessages(/*details*/ undefined, Diagnostics.Adding_a_tsconfig_json_file_will_help_organize_projects_that_contain_both_TypeScript_and_JavaScript_files_Learn_more_at_https_Colon_Slash_Slashaka_ms_Slashtsconfig);
3756                        }
3757                        chain = chainDiagnosticMessages(chain, Diagnostics.Cannot_write_file_0_because_it_would_overwrite_input_file, emitFileName);
3758                        blockEmittingOfFile(emitFileName, createCompilerDiagnosticFromMessageChain(chain));
3759                    }
3760
3761                    const emitFileKey = !host.useCaseSensitiveFileNames() ? toFileNameLowerCase(emitFilePath) : emitFilePath;
3762                    // Report error if multiple files write into same file
3763                    if (emitFilesSeen.has(emitFileKey)) {
3764                        // Already seen the same emit file - report error
3765                        blockEmittingOfFile(emitFileName, createCompilerDiagnostic(Diagnostics.Cannot_write_file_0_because_it_would_be_overwritten_by_multiple_input_files, emitFileName));
3766                    }
3767                    else {
3768                        emitFilesSeen.add(emitFileKey);
3769                    }
3770                }
3771            }
3772        }
3773
3774        function createDiagnosticExplainingFile(file: SourceFile | undefined, fileProcessingReason: FileIncludeReason | undefined, diagnostic: DiagnosticMessage, args: (string | number | undefined)[] | undefined): Diagnostic {
3775            let fileIncludeReasons: DiagnosticMessageChain[] | undefined;
3776            let relatedInfo: Diagnostic[] | undefined;
3777            let locationReason = isReferencedFile(fileProcessingReason) ? fileProcessingReason : undefined;
3778            if (file) fileReasons.get(file.path)?.forEach(processReason);
3779            if (fileProcessingReason) processReason(fileProcessingReason);
3780            // If we have location and there is only one reason file is in which is the location, dont add details for file include
3781            if (locationReason && fileIncludeReasons?.length === 1) fileIncludeReasons = undefined;
3782            const location = locationReason && getReferencedFileLocation(getSourceFileByPath, locationReason);
3783            const fileIncludeReasonDetails = fileIncludeReasons && chainDiagnosticMessages(fileIncludeReasons, Diagnostics.The_file_is_in_the_program_because_Colon);
3784            const redirectInfo = file && explainIfFileIsRedirectAndImpliedFormat(file);
3785            const chain = chainDiagnosticMessages(redirectInfo ? fileIncludeReasonDetails ? [fileIncludeReasonDetails, ...redirectInfo] : redirectInfo : fileIncludeReasonDetails, diagnostic, ...args || emptyArray);
3786            return location && isReferenceFileLocation(location) ?
3787                createFileDiagnosticFromMessageChain(location.file, location.pos, location.end - location.pos, chain, relatedInfo) :
3788                createCompilerDiagnosticFromMessageChain(chain, relatedInfo);
3789
3790            function processReason(reason: FileIncludeReason) {
3791                (fileIncludeReasons ||= []).push(fileIncludeReasonToDiagnostics(program, reason));
3792                if (!locationReason && isReferencedFile(reason)) {
3793                    // Report error at first reference file or file currently in processing and dont report in related information
3794                    locationReason = reason;
3795                }
3796                else if (locationReason !== reason) {
3797                    relatedInfo = append(relatedInfo, fileIncludeReasonToRelatedInformation(reason));
3798                }
3799                // Remove fileProcessingReason if its already included in fileReasons of the program
3800                if (reason === fileProcessingReason) fileProcessingReason = undefined;
3801            }
3802        }
3803
3804        function addFilePreprocessingFileExplainingDiagnostic(file: SourceFile | undefined, fileProcessingReason: FileIncludeReason, diagnostic: DiagnosticMessage, args?: (string | number | undefined)[]) {
3805            (fileProcessingDiagnostics ||= []).push({
3806                kind: FilePreprocessingDiagnosticsKind.FilePreprocessingFileExplainingDiagnostic,
3807                file: file && file.path,
3808                fileProcessingReason,
3809                diagnostic,
3810                args
3811            });
3812        }
3813
3814        function addProgramDiagnosticExplainingFile(file: SourceFile, diagnostic: DiagnosticMessage, args?: (string | number | undefined)[]) {
3815            programDiagnostics.add(createDiagnosticExplainingFile(file, /*fileProcessingReason*/ undefined, diagnostic, args));
3816        }
3817
3818        function fileIncludeReasonToRelatedInformation(reason: FileIncludeReason): DiagnosticWithLocation | undefined {
3819            if (isReferencedFile(reason)) {
3820                const referenceLocation = getReferencedFileLocation(getSourceFileByPath, reason);
3821                let message: DiagnosticMessage;
3822                switch (reason.kind) {
3823                    case FileIncludeKind.Import:
3824                        message = Diagnostics.File_is_included_via_import_here;
3825                        break;
3826                    case FileIncludeKind.ReferenceFile:
3827                        message = Diagnostics.File_is_included_via_reference_here;
3828                        break;
3829                    case FileIncludeKind.TypeReferenceDirective:
3830                        message = Diagnostics.File_is_included_via_type_library_reference_here;
3831                        break;
3832                    case FileIncludeKind.LibReferenceDirective:
3833                        message = Diagnostics.File_is_included_via_library_reference_here;
3834                        break;
3835                    default:
3836                        Debug.assertNever(reason);
3837                }
3838                return isReferenceFileLocation(referenceLocation) ? createFileDiagnostic(
3839                    referenceLocation.file,
3840                    referenceLocation.pos,
3841                    referenceLocation.end - referenceLocation.pos,
3842                    message,
3843                ) : undefined;
3844            }
3845
3846            if (!options.configFile) return undefined;
3847            let configFileNode: Node | undefined;
3848            let message: DiagnosticMessage;
3849            switch (reason.kind) {
3850                case FileIncludeKind.RootFile:
3851                    if (!options.configFile.configFileSpecs) return undefined;
3852                    const fileName = getNormalizedAbsolutePath(rootNames[reason.index], currentDirectory);
3853                    const matchedByFiles = getMatchedFileSpec(program, fileName);
3854                    if (matchedByFiles) {
3855                        configFileNode = getTsConfigPropArrayElementValue(options.configFile, "files", matchedByFiles);
3856                        message = Diagnostics.File_is_matched_by_files_list_specified_here;
3857                        break;
3858                    }
3859                    const matchedByInclude = getMatchedIncludeSpec(program, fileName);
3860                    // Could be additional files specified as roots
3861                    if (!matchedByInclude || !isString(matchedByInclude)) return undefined;
3862                    configFileNode = getTsConfigPropArrayElementValue(options.configFile, "include", matchedByInclude);
3863                    message = Diagnostics.File_is_matched_by_include_pattern_specified_here;
3864                    break;
3865                case FileIncludeKind.SourceFromProjectReference:
3866                case FileIncludeKind.OutputFromProjectReference:
3867                    const referencedResolvedRef = Debug.checkDefined(resolvedProjectReferences?.[reason.index]);
3868                    const referenceInfo = forEachProjectReference(projectReferences, resolvedProjectReferences, (resolvedRef, parent, index) =>
3869                        resolvedRef === referencedResolvedRef ? { sourceFile: parent?.sourceFile || options.configFile!, index } : undefined
3870                    );
3871                    if (!referenceInfo) return undefined;
3872                    const { sourceFile, index } = referenceInfo;
3873                    const referencesSyntax = firstDefined(getTsConfigPropArray(sourceFile as TsConfigSourceFile, "references"),
3874                        property => isArrayLiteralExpression(property.initializer) ? property.initializer : undefined);
3875                    return referencesSyntax && referencesSyntax.elements.length > index ?
3876                        createDiagnosticForNodeInSourceFile(
3877                            sourceFile,
3878                            referencesSyntax.elements[index],
3879                            reason.kind === FileIncludeKind.OutputFromProjectReference ?
3880                                Diagnostics.File_is_output_from_referenced_project_specified_here :
3881                                Diagnostics.File_is_source_from_referenced_project_specified_here,
3882                        ) :
3883                        undefined;
3884                case FileIncludeKind.AutomaticTypeDirectiveFile:
3885                    if (!options.types) return undefined;
3886                    configFileNode = getOptionsSyntaxByArrayElementValue("types", reason.typeReference);
3887                    message = Diagnostics.File_is_entry_point_of_type_library_specified_here;
3888                    break;
3889                case FileIncludeKind.LibFile:
3890                    if (reason.index !== undefined) {
3891                        configFileNode = getOptionsSyntaxByArrayElementValue("lib", options.lib![reason.index]);
3892                        message = Diagnostics.File_is_library_specified_here;
3893                        break;
3894                    }
3895                    const target = forEachEntry(targetOptionDeclaration.type, (value, key) => value === getEmitScriptTarget(options) ? key : undefined);
3896                    configFileNode = target ? getOptionsSyntaxByValue("target", target) : undefined;
3897                    message = Diagnostics.File_is_default_library_for_target_specified_here;
3898                    break;
3899                default:
3900                    Debug.assertNever(reason);
3901            }
3902            return configFileNode && createDiagnosticForNodeInSourceFile(
3903                options.configFile,
3904                configFileNode,
3905                message,
3906            );
3907        }
3908
3909        function verifyProjectReferences() {
3910            const buildInfoPath = !options.suppressOutputPathCheck ? getTsBuildInfoEmitOutputFilePath(options) : undefined;
3911            forEachProjectReference(projectReferences, resolvedProjectReferences, (resolvedRef, parent, index) => {
3912                const ref = (parent ? parent.commandLine.projectReferences : projectReferences)![index];
3913                const parentFile = parent && parent.sourceFile as JsonSourceFile;
3914                if (!resolvedRef) {
3915                    createDiagnosticForReference(parentFile, index, Diagnostics.File_0_not_found, ref.path);
3916                    return;
3917                }
3918                const options = resolvedRef.commandLine.options;
3919                if (!options.composite || options.noEmit) {
3920                    // ok to not have composite if the current program is container only
3921                    const inputs = parent ? parent.commandLine.fileNames : rootNames;
3922                    if (inputs.length) {
3923                        if (!options.composite) createDiagnosticForReference(parentFile, index, Diagnostics.Referenced_project_0_must_have_setting_composite_Colon_true, ref.path);
3924                        if (options.noEmit) createDiagnosticForReference(parentFile, index, Diagnostics.Referenced_project_0_may_not_disable_emit, ref.path);
3925                    }
3926                }
3927                if (ref.prepend) {
3928                    const out = outFile(options);
3929                    if (out) {
3930                        if (!host.fileExists(out)) {
3931                            createDiagnosticForReference(parentFile, index, Diagnostics.Output_file_0_from_project_1_does_not_exist, out, ref.path);
3932                        }
3933                    }
3934                    else {
3935                        createDiagnosticForReference(parentFile, index, Diagnostics.Cannot_prepend_project_0_because_it_does_not_have_outFile_set, ref.path);
3936                    }
3937                }
3938                if (!parent && buildInfoPath && buildInfoPath === getTsBuildInfoEmitOutputFilePath(options)) {
3939                    createDiagnosticForReference(parentFile, index, Diagnostics.Cannot_write_file_0_because_it_will_overwrite_tsbuildinfo_file_generated_by_referenced_project_1, buildInfoPath, ref.path);
3940                    hasEmitBlockingDiagnostics.set(toPath(buildInfoPath), true);
3941                }
3942            });
3943        }
3944
3945        function createDiagnosticForOptionPathKeyValue(key: string, valueIndex: number, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number) {
3946            let needCompilerDiagnostic = true;
3947            const pathsSyntax = getOptionPathsSyntax();
3948            for (const pathProp of pathsSyntax) {
3949                if (isObjectLiteralExpression(pathProp.initializer)) {
3950                    for (const keyProps of getPropertyAssignment(pathProp.initializer, key)) {
3951                        const initializer = keyProps.initializer;
3952                        if (isArrayLiteralExpression(initializer) && initializer.elements.length > valueIndex) {
3953                            programDiagnostics.add(createDiagnosticForNodeInSourceFile(options.configFile!, initializer.elements[valueIndex], message, arg0, arg1, arg2));
3954                            needCompilerDiagnostic = false;
3955                        }
3956                    }
3957                }
3958            }
3959
3960            if (needCompilerDiagnostic) {
3961                programDiagnostics.add(createCompilerDiagnostic(message, arg0, arg1, arg2));
3962            }
3963        }
3964
3965        function createDiagnosticForOptionPaths(onKey: boolean, key: string, message: DiagnosticMessage, arg0: string | number) {
3966            let needCompilerDiagnostic = true;
3967            const pathsSyntax = getOptionPathsSyntax();
3968            for (const pathProp of pathsSyntax) {
3969                if (isObjectLiteralExpression(pathProp.initializer) &&
3970                    createOptionDiagnosticInObjectLiteralSyntax(
3971                        pathProp.initializer, onKey, key, /*key2*/ undefined,
3972                        message, arg0)) {
3973                    needCompilerDiagnostic = false;
3974                }
3975            }
3976            if (needCompilerDiagnostic) {
3977                programDiagnostics.add(createCompilerDiagnostic(message, arg0));
3978            }
3979        }
3980
3981        function getOptionsSyntaxByName(name: string) {
3982            const compilerOptionsObjectLiteralSyntax = getCompilerOptionsObjectLiteralSyntax();
3983            return compilerOptionsObjectLiteralSyntax && getPropertyAssignment(compilerOptionsObjectLiteralSyntax, name);
3984        }
3985
3986        function getOptionPathsSyntax() {
3987            return getOptionsSyntaxByName("paths") || emptyArray;
3988        }
3989
3990        function getOptionsSyntaxByValue(name: string, value: string) {
3991            const syntaxByName = getOptionsSyntaxByName(name);
3992            return syntaxByName && firstDefined(syntaxByName, property => isStringLiteral(property.initializer) && property.initializer.text === value ? property.initializer : undefined);
3993        }
3994
3995        function getOptionsSyntaxByArrayElementValue(name: string, value: string) {
3996            const compilerOptionsObjectLiteralSyntax = getCompilerOptionsObjectLiteralSyntax();
3997            return compilerOptionsObjectLiteralSyntax && getPropertyArrayElementValue(compilerOptionsObjectLiteralSyntax, name, value);
3998        }
3999
4000        function createDiagnosticForOptionName(message: DiagnosticMessage, option1: string, option2?: string, option3?: string) {
4001            createDiagnosticForOption(/*onKey*/ true, option1, option2, message, option1, option2, option3);
4002        }
4003
4004        function createOptionValueDiagnostic(option1: string, message: DiagnosticMessage, arg0?: string, arg1?: string) {
4005            createDiagnosticForOption(/*onKey*/ false, option1, /*option2*/ undefined, message, arg0, arg1);
4006        }
4007
4008        function createDiagnosticForReference(sourceFile: JsonSourceFile | undefined, index: number, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number) {
4009            const referencesSyntax = firstDefined(getTsConfigPropArray(sourceFile || options.configFile, "references"),
4010                property => isArrayLiteralExpression(property.initializer) ? property.initializer : undefined);
4011            if (referencesSyntax && referencesSyntax.elements.length > index) {
4012                programDiagnostics.add(createDiagnosticForNodeInSourceFile(sourceFile || options.configFile!, referencesSyntax.elements[index], message, arg0, arg1));
4013            }
4014            else {
4015                programDiagnostics.add(createCompilerDiagnostic(message, arg0, arg1));
4016            }
4017        }
4018
4019        function createDiagnosticForOption(onKey: boolean, option1: string, option2: string | undefined, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number) {
4020            const compilerOptionsObjectLiteralSyntax = getCompilerOptionsObjectLiteralSyntax();
4021            const needCompilerDiagnostic = !compilerOptionsObjectLiteralSyntax ||
4022                !createOptionDiagnosticInObjectLiteralSyntax(compilerOptionsObjectLiteralSyntax, onKey, option1, option2, message, arg0, arg1, arg2);
4023
4024            if (needCompilerDiagnostic) {
4025                programDiagnostics.add(createCompilerDiagnostic(message, arg0, arg1, arg2));
4026            }
4027        }
4028
4029        function getCompilerOptionsObjectLiteralSyntax() {
4030            if (_compilerOptionsObjectLiteralSyntax === undefined) {
4031                _compilerOptionsObjectLiteralSyntax = false;
4032                const jsonObjectLiteral = getTsConfigObjectLiteralExpression(options.configFile);
4033                if (jsonObjectLiteral) {
4034                    for (const prop of getPropertyAssignment(jsonObjectLiteral, "compilerOptions")) {
4035                        if (isObjectLiteralExpression(prop.initializer)) {
4036                            _compilerOptionsObjectLiteralSyntax = prop.initializer;
4037                            break;
4038                        }
4039                    }
4040                }
4041            }
4042            return _compilerOptionsObjectLiteralSyntax || undefined;
4043        }
4044
4045        function createOptionDiagnosticInObjectLiteralSyntax(objectLiteral: ObjectLiteralExpression, onKey: boolean, key1: string, key2: string | undefined, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number): boolean {
4046            const props = getPropertyAssignment(objectLiteral, key1, key2);
4047            for (const prop of props) {
4048                programDiagnostics.add(createDiagnosticForNodeInSourceFile(options.configFile!, onKey ? prop.name : prop.initializer, message, arg0, arg1, arg2));
4049            }
4050            return !!props.length;
4051        }
4052
4053        function blockEmittingOfFile(emitFileName: string, diag: Diagnostic) {
4054            hasEmitBlockingDiagnostics.set(toPath(emitFileName), true);
4055            programDiagnostics.add(diag);
4056        }
4057
4058        function isEmittedFile(file: string): boolean {
4059            if (options.noEmit) {
4060                return false;
4061            }
4062
4063            // If this is source file, its not emitted file
4064            const filePath = toPath(file);
4065            if (getSourceFileByPath(filePath)) {
4066                return false;
4067            }
4068
4069            // If options have --outFile or --out just check that
4070            const out = outFile(options);
4071            if (out) {
4072                return isSameFile(filePath, out) || isSameFile(filePath, removeFileExtension(out) + Extension.Dts);
4073            }
4074
4075            // If declarationDir is specified, return if its a file in that directory
4076            if (options.declarationDir && containsPath(options.declarationDir, filePath, currentDirectory, !host.useCaseSensitiveFileNames())) {
4077                return true;
4078            }
4079
4080            // If --outDir, check if file is in that directory
4081            if (options.outDir) {
4082                return containsPath(options.outDir, filePath, currentDirectory, !host.useCaseSensitiveFileNames());
4083            }
4084
4085            if (fileExtensionIsOneOf(filePath, supportedJSExtensionsFlat) || isDeclarationFileName(filePath)) {
4086                // Otherwise just check if sourceFile with the name exists
4087                const filePathWithoutExtension = removeFileExtension(filePath);
4088                return !!getSourceFileByPath((filePathWithoutExtension + Extension.Ts) as Path) ||
4089                    !!getSourceFileByPath((filePathWithoutExtension + Extension.Tsx) as Path);
4090            }
4091            return false;
4092        }
4093
4094        function isSameFile(file1: string, file2: string) {
4095            return comparePaths(file1, file2, currentDirectory, !host.useCaseSensitiveFileNames()) === Comparison.EqualTo;
4096        }
4097
4098        function getSymlinkCache(): SymlinkCache {
4099            if (host.getSymlinkCache) {
4100                return host.getSymlinkCache();
4101            }
4102            if (!symlinks) {
4103                symlinks = createSymlinkCache(currentDirectory, getCanonicalFileName, isOhpm(options.packageManagerType));
4104            }
4105            if (files && resolvedTypeReferenceDirectives && !symlinks.hasProcessedResolutions()) {
4106                symlinks.setSymlinksFromResolutions(files, resolvedTypeReferenceDirectives);
4107            }
4108            return symlinks;
4109        }
4110    }
4111
4112    interface HostForUseSourceOfProjectReferenceRedirect {
4113        compilerHost: CompilerHost;
4114        getSymlinkCache: () => SymlinkCache;
4115        useSourceOfProjectReferenceRedirect: boolean;
4116        toPath(fileName: string): Path;
4117        getResolvedProjectReferences(): readonly (ResolvedProjectReference | undefined)[] | undefined;
4118        getSourceOfProjectReferenceRedirect(path: Path): SourceOfProjectReferenceRedirect | undefined;
4119        forEachResolvedProjectReference<T>(cb: (resolvedProjectReference: ResolvedProjectReference) => T | undefined): T | undefined;
4120        options?: CompilerOptions;
4121    }
4122
4123    function updateHostForUseSourceOfProjectReferenceRedirect(host: HostForUseSourceOfProjectReferenceRedirect) {
4124        let setOfDeclarationDirectories: Set<Path> | undefined;
4125        const originalFileExists = host.compilerHost.fileExists;
4126        const originalDirectoryExists = host.compilerHost.directoryExists;
4127        const originalGetDirectories = host.compilerHost.getDirectories;
4128        const originalRealpath = host.compilerHost.realpath;
4129
4130        if (!host.useSourceOfProjectReferenceRedirect) return { onProgramCreateComplete: noop, fileExists };
4131
4132        host.compilerHost.fileExists = fileExists;
4133
4134        let directoryExists;
4135        if (originalDirectoryExists) {
4136            // This implementation of directoryExists checks if the directory being requested is
4137            // directory of .d.ts file for the referenced Project.
4138            // If it is it returns true irrespective of whether that directory exists on host
4139            directoryExists = host.compilerHost.directoryExists = path => {
4140                if (originalDirectoryExists.call(host.compilerHost, path)) {
4141                    handleDirectoryCouldBeSymlink(path);
4142                    return true;
4143                }
4144
4145                if (!host.getResolvedProjectReferences()) return false;
4146
4147                if (!setOfDeclarationDirectories) {
4148                    setOfDeclarationDirectories = new Set();
4149                    host.forEachResolvedProjectReference(ref => {
4150                        const out = outFile(ref.commandLine.options);
4151                        if (out) {
4152                            setOfDeclarationDirectories!.add(getDirectoryPath(host.toPath(out)));
4153                        }
4154                        else {
4155                            // Set declaration's in different locations only, if they are next to source the directory present doesnt change
4156                            const declarationDir = ref.commandLine.options.declarationDir || ref.commandLine.options.outDir;
4157                            if (declarationDir) {
4158                                setOfDeclarationDirectories!.add(host.toPath(declarationDir));
4159                            }
4160                        }
4161                    });
4162                }
4163
4164                return fileOrDirectoryExistsUsingSource(path, /*isFile*/ false);
4165            };
4166        }
4167
4168        if (originalGetDirectories) {
4169            // Call getDirectories only if directory actually present on the host
4170            // This is needed to ensure that we arent getting directories that we fake about presence for
4171            host.compilerHost.getDirectories = path =>
4172                !host.getResolvedProjectReferences() || (originalDirectoryExists && originalDirectoryExists.call(host.compilerHost, path)) ?
4173                    originalGetDirectories.call(host.compilerHost, path) :
4174                    [];
4175        }
4176
4177        // This is something we keep for life time of the host
4178        if (originalRealpath) {
4179            host.compilerHost.realpath = s =>
4180                host.getSymlinkCache().getSymlinkedFiles()?.get(host.toPath(s)) ||
4181                originalRealpath.call(host.compilerHost, s);
4182        }
4183
4184        return { onProgramCreateComplete, fileExists, directoryExists };
4185
4186        function onProgramCreateComplete() {
4187            host.compilerHost.fileExists = originalFileExists;
4188            host.compilerHost.directoryExists = originalDirectoryExists;
4189            host.compilerHost.getDirectories = originalGetDirectories;
4190            // DO not revert realpath as it could be used later
4191        }
4192
4193        // This implementation of fileExists checks if the file being requested is
4194        // .d.ts file for the referenced Project.
4195        // If it is it returns true irrespective of whether that file exists on host
4196        function fileExists(file: string) {
4197            if (originalFileExists.call(host.compilerHost, file)) return true;
4198            if (!host.getResolvedProjectReferences()) return false;
4199            if (!isDeclarationFileName(file)) return false;
4200
4201            // Project references go to source file instead of .d.ts file
4202            return fileOrDirectoryExistsUsingSource(file, /*isFile*/ true);
4203        }
4204
4205        function fileExistsIfProjectReferenceDts(file: string) {
4206            const source = host.getSourceOfProjectReferenceRedirect(host.toPath(file));
4207            return source !== undefined ?
4208                isString(source) ? originalFileExists.call(host.compilerHost, source) as boolean : true :
4209                undefined;
4210        }
4211
4212        function directoryExistsIfProjectReferenceDeclDir(dir: string) {
4213            const dirPath = host.toPath(dir);
4214            const dirPathWithTrailingDirectorySeparator = `${dirPath}${directorySeparator}`;
4215            return forEachKey(
4216                setOfDeclarationDirectories!,
4217                declDirPath => dirPath === declDirPath ||
4218                    // Any parent directory of declaration dir
4219                    startsWith(declDirPath, dirPathWithTrailingDirectorySeparator) ||
4220                    // Any directory inside declaration dir
4221                    startsWith(dirPath, `${declDirPath}/`)
4222            );
4223        }
4224
4225        function handleDirectoryCouldBeSymlink(directory: string) {
4226            if (!host.getResolvedProjectReferences() || containsIgnoredPath(directory)) return;
4227
4228            // Because we already watch node_modules or oh_modules, handle symlinks in there
4229            const modulesPathPart = getModulePathPartByPMType(host.options?.packageManagerType);
4230            if (!originalRealpath || !stringContains(directory, modulesPathPart)) return;
4231            const symlinkCache = host.getSymlinkCache();
4232            const directoryPath = ensureTrailingDirectorySeparator(host.toPath(directory));
4233            if (symlinkCache.getSymlinkedDirectories()?.has(directoryPath)) return;
4234
4235            const real = normalizePath(originalRealpath.call(host.compilerHost, directory));
4236            let realPath: Path;
4237            if (real === directory ||
4238                (realPath = ensureTrailingDirectorySeparator(host.toPath(real))) === directoryPath) {
4239                // not symlinked
4240                symlinkCache.setSymlinkedDirectory(directoryPath, false);
4241                return;
4242            }
4243
4244            symlinkCache.setSymlinkedDirectory(directory, {
4245                real: ensureTrailingDirectorySeparator(real),
4246                realPath
4247            });
4248        }
4249
4250        function fileOrDirectoryExistsUsingSource(fileOrDirectory: string, isFile: boolean): boolean {
4251            const fileOrDirectoryExistsUsingSource = isFile ?
4252                (file: string) => fileExistsIfProjectReferenceDts(file) :
4253                (dir: string) => directoryExistsIfProjectReferenceDeclDir(dir);
4254            // Check current directory or file
4255            const result = fileOrDirectoryExistsUsingSource(fileOrDirectory);
4256            if (result !== undefined) return result;
4257
4258            const symlinkCache = host.getSymlinkCache();
4259            const symlinkedDirectories = symlinkCache.getSymlinkedDirectories();
4260            if (!symlinkedDirectories) return false;
4261            const fileOrDirectoryPath = host.toPath(fileOrDirectory);
4262            const modulesPathPart = getModulePathPartByPMType(host.options?.packageManagerType);
4263            if (!stringContains(fileOrDirectoryPath, modulesPathPart)) return false;
4264            if (isFile && symlinkCache.getSymlinkedFiles()?.has(fileOrDirectoryPath)) return true;
4265
4266            // If it contains node_modules or oh_modules check if its one of the symlinked path we know of
4267            return firstDefinedIterator(
4268                symlinkedDirectories.entries(),
4269                ([directoryPath, symlinkedDirectory]) => {
4270                    if (!symlinkedDirectory || !startsWith(fileOrDirectoryPath, directoryPath)) return undefined;
4271                    const result = fileOrDirectoryExistsUsingSource(fileOrDirectoryPath.replace(directoryPath, symlinkedDirectory.realPath));
4272                    if (isFile && result) {
4273                        // Store the real path for the file'
4274                        const absolutePath = getNormalizedAbsolutePath(fileOrDirectory, host.compilerHost.getCurrentDirectory());
4275                        symlinkCache.setSymlinkedFile(
4276                            fileOrDirectoryPath,
4277                            `${symlinkedDirectory.real}${absolutePath.replace(new RegExp(directoryPath, "i"), "")}`
4278                        );
4279                    }
4280                    return result;
4281                }
4282            ) || false;
4283        }
4284    }
4285
4286    /*@internal*/
4287    export const emitSkippedWithNoDiagnostics: EmitResult = { diagnostics: emptyArray, sourceMaps: undefined, emittedFiles: undefined, emitSkipped: true };
4288
4289    /*@internal*/
4290    export function handleNoEmitOptions<T extends BuilderProgram>(
4291        program: Program | T,
4292        sourceFile: SourceFile | undefined,
4293        writeFile: WriteFileCallback | undefined,
4294        cancellationToken: CancellationToken | undefined
4295    ): EmitResult | undefined {
4296        const options = program.getCompilerOptions();
4297        if (options.noEmit) {
4298            // Cache the semantic diagnostics
4299            program.getSemanticDiagnostics(sourceFile, cancellationToken);
4300            return sourceFile || outFile(options) ?
4301                emitSkippedWithNoDiagnostics :
4302                program.emitBuildInfo(writeFile, cancellationToken);
4303        }
4304
4305        // If the noEmitOnError flag is set, then check if we have any errors so far.  If so,
4306        // immediately bail out.  Note that we pass 'undefined' for 'sourceFile' so that we
4307        // get any preEmit diagnostics, not just the ones
4308        if (!options.noEmitOnError) return undefined;
4309        let diagnostics: readonly Diagnostic[] = [
4310            ...program.getOptionsDiagnostics(cancellationToken),
4311            ...program.getSyntacticDiagnostics(sourceFile, cancellationToken),
4312            ...program.getGlobalDiagnostics(cancellationToken),
4313            ...program.getSemanticDiagnostics(sourceFile, cancellationToken)
4314        ];
4315
4316        if (diagnostics.length === 0 && getEmitDeclarations(program.getCompilerOptions())) {
4317            diagnostics = program.getDeclarationDiagnostics(/*sourceFile*/ undefined, cancellationToken);
4318        }
4319
4320        if (!diagnostics.length) return undefined;
4321        let emittedFiles: string[] | undefined;
4322        if (!sourceFile && !outFile(options)) {
4323            const emitResult = program.emitBuildInfo(writeFile, cancellationToken);
4324            if (emitResult.diagnostics) diagnostics = [...diagnostics, ...emitResult.diagnostics];
4325            emittedFiles = emitResult.emittedFiles;
4326        }
4327        return { diagnostics, sourceMaps: undefined, emittedFiles, emitSkipped: true };
4328    }
4329
4330    /*@internal*/
4331    export function filterSemanticDiagnostics(diagnostic: readonly Diagnostic[], option: CompilerOptions): readonly Diagnostic[] {
4332        return filter(diagnostic, d => !d.skippedOn || !option[d.skippedOn]);
4333    }
4334
4335    /*@internal*/
4336    interface CompilerHostLike {
4337        useCaseSensitiveFileNames(): boolean;
4338        getCurrentDirectory(): string;
4339        fileExists(fileName: string): boolean;
4340        readFile(fileName: string): string | undefined;
4341        readDirectory?(rootDir: string, extensions: readonly string[], excludes: readonly string[] | undefined, includes: readonly string[], depth?: number): string[];
4342        trace?(s: string): void;
4343        onUnRecoverableConfigFileDiagnostic?: DiagnosticReporter;
4344    }
4345
4346    /* @internal */
4347    export function parseConfigHostFromCompilerHostLike(host: CompilerHostLike, directoryStructureHost: DirectoryStructureHost = host): ParseConfigFileHost {
4348        return {
4349            fileExists: f => directoryStructureHost.fileExists(f),
4350            readDirectory(root, extensions, excludes, includes, depth) {
4351                Debug.assertIsDefined(directoryStructureHost.readDirectory, "'CompilerHost.readDirectory' must be implemented to correctly process 'projectReferences'");
4352                return directoryStructureHost.readDirectory(root, extensions, excludes, includes, depth);
4353            },
4354            readFile: f => directoryStructureHost.readFile(f),
4355            useCaseSensitiveFileNames: host.useCaseSensitiveFileNames(),
4356            getCurrentDirectory: () => host.getCurrentDirectory(),
4357            onUnRecoverableConfigFileDiagnostic: host.onUnRecoverableConfigFileDiagnostic || returnUndefined,
4358            trace: host.trace ? (s) => host.trace!(s) : undefined
4359        };
4360    }
4361
4362    // For backward compatibility
4363    /** @deprecated */ export interface ResolveProjectReferencePathHost {
4364        fileExists(fileName: string): boolean;
4365    }
4366
4367    /* @internal */
4368    export function createPrependNodes(projectReferences: readonly ProjectReference[] | undefined, getCommandLine: (ref: ProjectReference, index: number) => ParsedCommandLine | undefined, readFile: (path: string) => string | undefined) {
4369        if (!projectReferences) return emptyArray;
4370        let nodes: InputFiles[] | undefined;
4371        for (let i = 0; i < projectReferences.length; i++) {
4372            const ref = projectReferences[i];
4373            const resolvedRefOpts = getCommandLine(ref, i);
4374            if (ref.prepend && resolvedRefOpts && resolvedRefOpts.options) {
4375                const out = outFile(resolvedRefOpts.options);
4376                // Upstream project didn't have outFile set -- skip (error will have been issued earlier)
4377                if (!out) continue;
4378
4379                const { jsFilePath, sourceMapFilePath, declarationFilePath, declarationMapPath, buildInfoPath } = getOutputPathsForBundle(resolvedRefOpts.options, /*forceDtsPaths*/ true);
4380                const node = createInputFiles(readFile, jsFilePath!, sourceMapFilePath, declarationFilePath!, declarationMapPath, buildInfoPath);
4381                (nodes || (nodes = [])).push(node);
4382            }
4383        }
4384        return nodes || emptyArray;
4385    }
4386    /**
4387     * Returns the target config filename of a project reference.
4388     * Note: The file might not exist.
4389     */
4390    export function resolveProjectReferencePath(ref: ProjectReference): ResolvedConfigFileName;
4391    /** @deprecated */ export function resolveProjectReferencePath(host: ResolveProjectReferencePathHost, ref: ProjectReference): ResolvedConfigFileName;
4392    export function resolveProjectReferencePath(hostOrRef: ResolveProjectReferencePathHost | ProjectReference, ref?: ProjectReference): ResolvedConfigFileName {
4393        const passedInRef = ref ? ref : hostOrRef as ProjectReference;
4394        return resolveConfigFileProjectName(passedInRef.path);
4395    }
4396
4397    /* @internal */
4398    /**
4399     * Returns a DiagnosticMessage if we won't include a resolved module due to its extension.
4400     * The DiagnosticMessage's parameters are the imported module name, and the filename it resolved to.
4401     * This returns a diagnostic even if the module will be an untyped module.
4402     */
4403    export function getResolutionDiagnostic(options: CompilerOptions, { extension }: ResolvedModuleFull): DiagnosticMessage | undefined {
4404        switch (extension) {
4405            case Extension.Ts:
4406            case Extension.Dts:
4407            case Extension.Ets:
4408            case Extension.Dets:
4409                // These are always allowed.
4410                return undefined;
4411            case Extension.Tsx:
4412                return needJsx();
4413            case Extension.Jsx:
4414                return needJsx() || needAllowJs();
4415            case Extension.Js:
4416                return needAllowJs();
4417            case Extension.Json:
4418                return needResolveJsonModule();
4419        }
4420
4421        function needJsx() {
4422            return options.jsx ? undefined : Diagnostics.Module_0_was_resolved_to_1_but_jsx_is_not_set;
4423        }
4424        function needAllowJs() {
4425            return getAllowJSCompilerOption(options) || !getStrictOptionValue(options, "noImplicitAny") ? undefined : Diagnostics.Could_not_find_a_declaration_file_for_module_0_1_implicitly_has_an_any_type;
4426        }
4427        function needResolveJsonModule() {
4428            return options.resolveJsonModule ? undefined : Diagnostics.Module_0_was_resolved_to_1_but_resolveJsonModule_is_not_used;
4429        }
4430    }
4431
4432    function getModuleNames({ imports, moduleAugmentations }: SourceFile): string[] {
4433        const res = imports.map(i => i.text);
4434        for (const aug of moduleAugmentations) {
4435            if (aug.kind === SyntaxKind.StringLiteral) {
4436                res.push(aug.text);
4437            }
4438            // Do nothing if it's an Identifier; we don't need to do module resolution for `declare global`.
4439        }
4440        return res;
4441    }
4442
4443    /* @internal */
4444    export function getModuleNameStringLiteralAt({ imports, moduleAugmentations }: SourceFileImportsList, index: number): StringLiteralLike {
4445        if (index < imports.length) return imports[index];
4446        let augIndex = imports.length;
4447        for (const aug of moduleAugmentations) {
4448            if (aug.kind === SyntaxKind.StringLiteral) {
4449                if (index === augIndex) return aug;
4450                augIndex++;
4451            }
4452            // Do nothing if it's an Identifier; we don't need to do module resolution for `declare global`.
4453        }
4454        Debug.fail("should never ask for module name at index higher than possible module name");
4455    }
4456}
4457