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 | undefined;
1036        let linterTypeChecker: TypeChecker | undefined;
1037        let classifiableNames: Set<__String>;
1038        const ambientModuleNameToUnmodifiedFileName = new Map<string, string>();
1039        let fileReasons = createMultiMap<Path, FileIncludeReason>();
1040        const cachedBindAndCheckDiagnosticsForFile: DiagnosticCache<Diagnostic> = {};
1041        const cachedBindAndCheckDiagnosticsForFileForLinter: DiagnosticCache<Diagnostic> = {};
1042        const cachedDeclarationDiagnosticsForFile: DiagnosticCache<DiagnosticWithLocation> = {};
1043
1044        let resolvedTypeReferenceDirectives = createModeAwareCache<ResolvedTypeReferenceDirective | undefined>();
1045        let fileProcessingDiagnostics: FilePreprocessingDiagnostics[] | undefined;
1046
1047        // 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.
1048        // This works as imported modules are discovered recursively in a depth first manner, specifically:
1049        // - For each root file, findSourceFile is called.
1050        // - This calls processImportedModules for each module imported in the source file.
1051        // - This calls resolveModuleNames, and then calls findSourceFile for each resolved module.
1052        // As all these operations happen - and are nested - within the createProgram call, they close over the below variables.
1053        // The current resolution depth is tracked by incrementing/decrementing as the depth first search progresses.
1054        const maxNodeModuleJsDepth = typeof options.maxNodeModuleJsDepth === "number" ? options.maxNodeModuleJsDepth : 0;
1055        let currentNodeModulesDepth = 0;
1056
1057        // If a module has some of its imports skipped due to being at the depth limit under node_modules or oh_modules, then track
1058        // this, as it may be imported at a shallower depth later, and then it will need its skipped imports processed.
1059        const modulesWithElidedImports = new Map<string, boolean>();
1060
1061        // Track source files that are source files found by searching under node_modules or oh_modules, as these shouldn't be compiled.
1062        const sourceFilesFoundSearchingNodeModules = new Map<string, boolean>();
1063
1064        tracing?.push(tracing.Phase.Program, "createProgram", { configFilePath: options.configFilePath, rootDir: options.rootDir }, /*separateBeginAndEnd*/ true);
1065        performance.mark("beforeProgram");
1066
1067        const host = createProgramOptions.host || createCompilerHost(options);
1068        const configParsingHost = parseConfigHostFromCompilerHostLike(host);
1069
1070        let skipDefaultLib = options.noLib;
1071        const getDefaultLibraryFileName = memoize(() => host.getDefaultLibFileName(options));
1072        const defaultLibraryPath = host.getDefaultLibLocation ? host.getDefaultLibLocation() : getDirectoryPath(getDefaultLibraryFileName());
1073        const programDiagnostics = createDiagnosticCollection();
1074        const currentDirectory = host.getCurrentDirectory();
1075        const supportedExtensions = getSupportedExtensions(options);
1076        const supportedExtensionsWithJsonIfResolveJsonModule = getSupportedExtensionsWithJsonIfResolveJsonModule(options, supportedExtensions);
1077
1078        // Map storing if there is emit blocking diagnostics for given input
1079        const hasEmitBlockingDiagnostics = new Map<string, boolean>();
1080        let _compilerOptionsObjectLiteralSyntax: ObjectLiteralExpression | false | undefined;
1081
1082        let moduleResolutionCache: ModuleResolutionCache | undefined;
1083        let typeReferenceDirectiveResolutionCache: TypeReferenceDirectiveResolutionCache | undefined;
1084        let actualResolveModuleNamesWorker: (moduleNames: string[], containingFile: SourceFile, containingFileName: string, reusedNames?: string[], redirectedReference?: ResolvedProjectReference) => ResolvedModuleFull[];
1085        const hasInvalidatedResolutions = host.hasInvalidatedResolutions || returnFalse;
1086        if (host.resolveModuleNames) {
1087            actualResolveModuleNamesWorker = (moduleNames, containingFile, containingFileName, reusedNames, redirectedReference) => host.resolveModuleNames!(Debug.checkEachDefined(moduleNames), containingFileName, reusedNames, redirectedReference, options, containingFile).map(resolved => {
1088                // An older host may have omitted extension, in which case we should infer it from the file extension of resolvedFileName.
1089                if (!resolved || (resolved as ResolvedModuleFull).extension !== undefined) {
1090                    return resolved as ResolvedModuleFull;
1091                }
1092                const withExtension = clone(resolved) as ResolvedModuleFull;
1093                withExtension.extension = extensionFromPath(resolved.resolvedFileName);
1094                return withExtension;
1095            });
1096            moduleResolutionCache = host.getModuleResolutionCache?.();
1097        }
1098        else {
1099            moduleResolutionCache = createModuleResolutionCache(currentDirectory, getCanonicalFileName, options);
1100            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
1101            actualResolveModuleNamesWorker = (moduleNames, containingFile, containingFileName, _reusedNames, redirectedReference) => loadWithModeAwareCache<ResolvedModuleFull>(Debug.checkEachDefined(moduleNames), containingFile, containingFileName, redirectedReference, loader);
1102        }
1103
1104        let actualResolveTypeReferenceDirectiveNamesWorker: (typeDirectiveNames: string[] | readonly FileReference[], containingFile: string, redirectedReference?: ResolvedProjectReference, containingFileMode?: SourceFile["impliedNodeFormat"] | undefined) => (ResolvedTypeReferenceDirective | undefined)[];
1105        if (host.resolveTypeReferenceDirectives) {
1106            actualResolveTypeReferenceDirectiveNamesWorker = (typeDirectiveNames, containingFile, redirectedReference, containingFileMode) => host.resolveTypeReferenceDirectives!(Debug.checkEachDefined(typeDirectiveNames), containingFile, redirectedReference, options, containingFileMode);
1107        }
1108        else {
1109            typeReferenceDirectiveResolutionCache = createTypeReferenceDirectiveResolutionCache(currentDirectory, getCanonicalFileName, /*options*/ undefined, moduleResolutionCache?.getPackageJsonInfoCache());
1110            const loader = (typesRef: string, containingFile: string, redirectedReference: ResolvedProjectReference | undefined, resolutionMode: SourceFile["impliedNodeFormat"] | undefined) => resolveTypeReferenceDirective(
1111                typesRef,
1112                containingFile,
1113                options,
1114                host,
1115                redirectedReference,
1116                typeReferenceDirectiveResolutionCache,
1117                resolutionMode,
1118            ).resolvedTypeReferenceDirective!; // TODO: GH#18217
1119            actualResolveTypeReferenceDirectiveNamesWorker = (typeReferenceDirectiveNames, containingFile, redirectedReference, containingFileMode) => loadWithTypeDirectiveCache<ResolvedTypeReferenceDirective>(Debug.checkEachDefined(typeReferenceDirectiveNames), containingFile, redirectedReference, containingFileMode, loader);
1120        }
1121
1122        // Map from a stringified PackageId to the source file with that id.
1123        // Only one source file may have a given packageId. Others become redirects (see createRedirectSourceFile).
1124        // `packageIdToSourceFile` is only used while building the program, while `sourceFileToPackageName` and `isSourceFileTargetOfRedirect` are kept around.
1125        const packageIdToSourceFile = new Map<string, SourceFile>();
1126        // Maps from a SourceFile's `.path` to the name of the package it was imported with.
1127        let sourceFileToPackageName = new Map<Path, string>();
1128        // Key is a file name. Value is the (non-empty, or undefined) list of files that redirect to it.
1129        let redirectTargetsMap = createMultiMap<Path, string>();
1130        let usesUriStyleNodeCoreModules = false;
1131
1132        /**
1133         * map with
1134         * - SourceFile if present
1135         * - false if sourceFile missing for source of project reference redirect
1136         * - undefined otherwise
1137         */
1138        const filesByName = new Map<string, SourceFile | false | undefined>();
1139        let missingFilePaths: readonly Path[] | undefined;
1140        // stores 'filename -> file association' ignoring case
1141        // used to track cases when two file names differ only in casing
1142        const filesByNameIgnoreCase = host.useCaseSensitiveFileNames() ? new Map<string, SourceFile>() : undefined;
1143
1144        // A parallel array to projectReferences storing the results of reading in the referenced tsconfig files
1145        let resolvedProjectReferences: readonly (ResolvedProjectReference | undefined)[] | undefined;
1146        let projectReferenceRedirects: ESMap<Path, ResolvedProjectReference | false> | undefined;
1147        let mapFromFileToProjectReferenceRedirects: ESMap<Path, Path> | undefined;
1148        let mapFromToProjectReferenceRedirectSource: ESMap<Path, SourceOfProjectReferenceRedirect> | undefined;
1149
1150        const useSourceOfProjectReferenceRedirect = !!host.useSourceOfProjectReferenceRedirect?.() &&
1151            !options.disableSourceOfProjectReferenceRedirect;
1152        const { onProgramCreateComplete, fileExists, directoryExists } = updateHostForUseSourceOfProjectReferenceRedirect({
1153            compilerHost: host,
1154            getSymlinkCache,
1155            useSourceOfProjectReferenceRedirect,
1156            toPath,
1157            getResolvedProjectReferences,
1158            getSourceOfProjectReferenceRedirect,
1159            forEachResolvedProjectReference,
1160            options: _options
1161        });
1162        const readFile = host.readFile.bind(host) as typeof host.readFile;
1163
1164        tracing?.push(tracing.Phase.Program, "shouldProgramCreateNewSourceFiles", { hasOldProgram: !!oldProgram });
1165        const shouldCreateNewSourceFile = shouldProgramCreateNewSourceFiles(oldProgram, options);
1166        tracing?.pop();
1167        // We set `structuralIsReused` to `undefined` because `tryReuseStructureFromOldProgram` calls `tryReuseStructureFromOldProgram` which checks
1168        // `structuralIsReused`, which would be a TDZ violation if it was not set in advance to `undefined`.
1169        let structureIsReused: StructureIsReused;
1170        tracing?.push(tracing.Phase.Program, "tryReuseStructureFromOldProgram", {});
1171        structureIsReused = tryReuseStructureFromOldProgram(); // eslint-disable-line prefer-const
1172        tracing?.pop();
1173        if (structureIsReused !== StructureIsReused.Completely) {
1174            processingDefaultLibFiles = [];
1175            processingOtherFiles = [];
1176
1177            if (projectReferences) {
1178                if (!resolvedProjectReferences) {
1179                    resolvedProjectReferences = projectReferences.map(parseProjectReferenceConfigFile);
1180                }
1181                if (rootNames.length) {
1182                    resolvedProjectReferences?.forEach((parsedRef, index) => {
1183                        if (!parsedRef) return;
1184                        const out = outFile(parsedRef.commandLine.options);
1185                        if (useSourceOfProjectReferenceRedirect) {
1186                            if (out || getEmitModuleKind(parsedRef.commandLine.options) === ModuleKind.None) {
1187                                for (const fileName of parsedRef.commandLine.fileNames) {
1188                                    processProjectReferenceFile(fileName, { kind: FileIncludeKind.SourceFromProjectReference, index });
1189                                }
1190                            }
1191                        }
1192                        else {
1193                            if (out) {
1194                                processProjectReferenceFile(changeExtension(out, ".d.ts"), { kind: FileIncludeKind.OutputFromProjectReference, index });
1195                            }
1196                            else if (getEmitModuleKind(parsedRef.commandLine.options) === ModuleKind.None) {
1197                                const getCommonSourceDirectory = memoize(() => getCommonSourceDirectoryOfConfig(parsedRef.commandLine, !host.useCaseSensitiveFileNames()));
1198                                for (const fileName of parsedRef.commandLine.fileNames) {
1199                                    if (!isDeclarationFileName(fileName) && !fileExtensionIs(fileName, Extension.Json)) {
1200                                        processProjectReferenceFile(getOutputDeclarationFileName(fileName, parsedRef.commandLine, !host.useCaseSensitiveFileNames(), getCommonSourceDirectory), { kind: FileIncludeKind.OutputFromProjectReference, index });
1201                                    }
1202                                }
1203                            }
1204                        }
1205                    });
1206                }
1207            }
1208
1209            tracing?.push(tracing.Phase.Program, "processRootFiles", { count: rootNames.length });
1210            forEach(rootNames, (name, index) => processRootFile(name, /*isDefaultLib*/ false, /*ignoreNoDefaultLib*/ false, { kind: FileIncludeKind.RootFile, index }));
1211            tracing?.pop();
1212
1213            // load type declarations specified via 'types' argument or implicitly from types/ and node_modules/@types folders
1214            const typeReferences: string[] = rootNames.length ? getAutomaticTypeDirectiveNames(options, host) : emptyArray;
1215
1216            if (typeReferences.length) {
1217                tracing?.push(tracing.Phase.Program, "processTypeReferences", { count: typeReferences.length });
1218                // This containingFilename needs to match with the one used in managed-side
1219                const containingDirectory = options.configFilePath ? getDirectoryPath(options.configFilePath) : host.getCurrentDirectory();
1220                const containingFilename = combinePaths(containingDirectory, inferredTypesContainingFile);
1221                const resolutions = resolveTypeReferenceDirectiveNamesWorker(typeReferences, containingFilename);
1222                for (let i = 0; i < typeReferences.length; i++) {
1223                    // under node16/nodenext module resolution, load `types`/ata include names as cjs resolution results by passing an `undefined` mode
1224                    processTypeReferenceDirective(typeReferences[i], /*mode*/ undefined, resolutions[i], { kind: FileIncludeKind.AutomaticTypeDirectiveFile, typeReference: typeReferences[i], packageId: resolutions[i]?.packageId });
1225                }
1226                tracing?.pop();
1227            }
1228
1229            // Do not process the default library if:
1230            //  - The '--noLib' flag is used.
1231            //  - A 'no-default-lib' reference comment is encountered in
1232            //      processing the root files.
1233            if (rootNames.length && !skipDefaultLib) {
1234                // If '--lib' is not specified, include default library file according to '--target'
1235                // otherwise, using options specified in '--lib' instead of '--target' default library file
1236                const defaultLibraryFileName = getDefaultLibraryFileName();
1237                if (!options.lib && defaultLibraryFileName) {
1238                    processRootFile(defaultLibraryFileName, /*isDefaultLib*/ true, /*ignoreNoDefaultLib*/ false, { kind: FileIncludeKind.LibFile });
1239                }
1240                else {
1241                    forEach(options.lib, (libFileName, index) => {
1242                        processRootFile(pathForLibFile(libFileName), /*isDefaultLib*/ true, /*ignoreNoDefaultLib*/ false, { kind: FileIncludeKind.LibFile, index });
1243                    });
1244
1245                    const etsComponentsLib = options.ets?.libs ?? [];
1246                    if (etsComponentsLib.length) {
1247                        forEach(etsComponentsLib, libFileName => {
1248                            processRootFile(combinePaths(libFileName), /*isDefaultLib*/ true, /*ignoreNoDefaultLib*/ false, { kind: FileIncludeKind.LibFile });
1249                        });
1250                    }
1251                }
1252            }
1253
1254            missingFilePaths = arrayFrom(mapDefinedIterator(filesByName.entries(), ([path, file]) => file === undefined ? path as Path : undefined));
1255            files = stableSort(processingDefaultLibFiles, compareDefaultLibFiles).concat(processingOtherFiles);
1256            processingDefaultLibFiles = undefined;
1257            processingOtherFiles = undefined;
1258        }
1259
1260        Debug.assert(!!missingFilePaths);
1261
1262        // Release any files we have acquired in the old program but are
1263        // not part of the new program.
1264        if (oldProgram && host.onReleaseOldSourceFile) {
1265            const oldSourceFiles = oldProgram.getSourceFiles();
1266            for (const oldSourceFile of oldSourceFiles) {
1267                const newFile = getSourceFileByPath(oldSourceFile.resolvedPath);
1268                if (shouldCreateNewSourceFile || !newFile || newFile.impliedNodeFormat !== oldSourceFile.impliedNodeFormat ||
1269                    // old file wasn't redirect but new file is
1270                    (oldSourceFile.resolvedPath === oldSourceFile.path && newFile.resolvedPath !== oldSourceFile.path)) {
1271                    host.onReleaseOldSourceFile(oldSourceFile, oldProgram.getCompilerOptions(), !!getSourceFileByPath(oldSourceFile.path));
1272                }
1273            }
1274            if (!host.getParsedCommandLine) {
1275                oldProgram.forEachResolvedProjectReference(resolvedProjectReference => {
1276                    if (!getResolvedProjectReferenceByPath(resolvedProjectReference.sourceFile.path)) {
1277                        host.onReleaseOldSourceFile!(resolvedProjectReference.sourceFile, oldProgram!.getCompilerOptions(), /*hasSourceFileByPath*/ false);
1278                    }
1279                });
1280            }
1281        }
1282
1283        // Release commandlines that new program does not use
1284        if (oldProgram && host.onReleaseParsedCommandLine) {
1285            forEachProjectReference(
1286                oldProgram.getProjectReferences(),
1287                oldProgram.getResolvedProjectReferences(),
1288                (oldResolvedRef, parent, index) => {
1289                    const oldReference = parent?.commandLine.projectReferences![index] || oldProgram!.getProjectReferences()![index];
1290                    const oldRefPath = resolveProjectReferencePath(oldReference);
1291                    if (!projectReferenceRedirects?.has(toPath(oldRefPath))) {
1292                        host.onReleaseParsedCommandLine!(oldRefPath, oldResolvedRef, oldProgram!.getCompilerOptions());
1293                    }
1294                }
1295            );
1296        }
1297
1298        typeReferenceDirectiveResolutionCache = undefined;
1299
1300        // unconditionally set oldProgram to undefined to prevent it from being captured in closure
1301        oldProgram = undefined;
1302
1303        const program: Program = {
1304            getRootFileNames: () => rootNames,
1305            getSourceFile,
1306            getSourceFileByPath,
1307            getSourceFiles: () => files,
1308            getMissingFilePaths: () => missingFilePaths!, // TODO: GH#18217
1309            getModuleResolutionCache: () => moduleResolutionCache,
1310            getFilesByNameMap: () => filesByName,
1311            getCompilerOptions: () => options,
1312            getSyntacticDiagnostics,
1313            getOptionsDiagnostics,
1314            getGlobalDiagnostics,
1315            getSemanticDiagnostics,
1316            getSemanticDiagnosticsForLinter,
1317            getCachedSemanticDiagnostics,
1318            getSuggestionDiagnostics,
1319            getDeclarationDiagnostics,
1320            getBindAndCheckDiagnostics,
1321            getProgramDiagnostics,
1322            getTypeChecker,
1323            getLinterTypeChecker,
1324            getEtsLibSFromProgram,
1325            getClassifiableNames,
1326            getCommonSourceDirectory,
1327            emit,
1328            getCurrentDirectory: () => currentDirectory,
1329            getNodeCount: () => getTypeChecker().getNodeCount(),
1330            getIdentifierCount: () => getTypeChecker().getIdentifierCount(),
1331            getSymbolCount: () => getTypeChecker().getSymbolCount(),
1332            getTypeCount: () => getTypeChecker().getTypeCount(),
1333            getInstantiationCount: () => getTypeChecker().getInstantiationCount(),
1334            getRelationCacheSizes: () => getTypeChecker().getRelationCacheSizes(),
1335            getFileProcessingDiagnostics: () => fileProcessingDiagnostics,
1336            getResolvedTypeReferenceDirectives: () => resolvedTypeReferenceDirectives,
1337            isSourceFileFromExternalLibrary,
1338            isSourceFileDefaultLibrary,
1339            getSourceFileFromReference,
1340            getLibFileFromReference,
1341            sourceFileToPackageName,
1342            redirectTargetsMap,
1343            usesUriStyleNodeCoreModules,
1344            isEmittedFile,
1345            getConfigFileParsingDiagnostics,
1346            getResolvedModuleWithFailedLookupLocationsFromCache,
1347            getProjectReferences,
1348            getResolvedProjectReferences,
1349            getProjectReferenceRedirect,
1350            getResolvedProjectReferenceToRedirect,
1351            getResolvedProjectReferenceByPath,
1352            forEachResolvedProjectReference,
1353            isSourceOfProjectReferenceRedirect,
1354            emitBuildInfo,
1355            fileExists,
1356            readFile,
1357            directoryExists,
1358            getSymlinkCache,
1359            realpath: host.realpath?.bind(host),
1360            useCaseSensitiveFileNames: () => host.useCaseSensitiveFileNames(),
1361            getFileIncludeReasons: () => fileReasons,
1362            structureIsReused,
1363            writeFile,
1364            getJsDocNodeCheckedConfig: host.getJsDocNodeCheckedConfig,
1365            getJsDocNodeConditionCheckedResult: host. getJsDocNodeConditionCheckedResult,
1366            getFileCheckedModuleInfo: host.getFileCheckedModuleInfo,
1367            releaseTypeChecker: () => { typeChecker = undefined; linterTypeChecker = undefined; },
1368            getEmitHost
1369        };
1370
1371        onProgramCreateComplete();
1372
1373        // Add file processingDiagnostics
1374        fileProcessingDiagnostics?.forEach(diagnostic => {
1375            switch (diagnostic.kind) {
1376                case FilePreprocessingDiagnosticsKind.FilePreprocessingFileExplainingDiagnostic:
1377                    return programDiagnostics.add(createDiagnosticExplainingFile(diagnostic.file && getSourceFileByPath(diagnostic.file), diagnostic.fileProcessingReason, diagnostic.diagnostic, diagnostic.args || emptyArray));
1378                case FilePreprocessingDiagnosticsKind.FilePreprocessingReferencedDiagnostic:
1379                    const { file, pos, end } = getReferencedFileLocation(getSourceFileByPath, diagnostic.reason) as ReferenceFileLocation;
1380                    return programDiagnostics.add(createFileDiagnostic(file, Debug.checkDefined(pos), Debug.checkDefined(end) - pos, diagnostic.diagnostic, ...diagnostic.args || emptyArray));
1381                default:
1382                    Debug.assertNever(diagnostic);
1383            }
1384        });
1385
1386        verifyCompilerOptions();
1387        performance.mark("afterProgram");
1388        performance.measure("Program", "beforeProgram", "afterProgram");
1389        tracing?.pop();
1390
1391        return program;
1392
1393        function addResolutionDiagnostics(list: Diagnostic[] | undefined) {
1394            if (!list) return;
1395            for (const elem of list) {
1396                programDiagnostics.add(elem);
1397            }
1398        }
1399
1400        function pullDiagnosticsFromCache(names: string[] | readonly FileReference[], containingFile: SourceFile) {
1401            if (!moduleResolutionCache) return;
1402            const containingFileName = getNormalizedAbsolutePath(containingFile.originalFileName, currentDirectory);
1403            const containingFileMode = !isString(containingFile) ? containingFile.impliedNodeFormat : undefined;
1404            const containingDir = getDirectoryPath(containingFileName);
1405            const redirectedReference = getRedirectReferenceForResolution(containingFile);
1406            let i = 0;
1407            for (const n of names) {
1408                // 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
1409                const mode = typeof n === "string" ? getModeForResolutionAtIndex(containingFile, i) : getModeForFileReference(n, containingFileMode);
1410                const name = typeof n === "string" ? n : n.fileName;
1411                i++;
1412                // only nonrelative names hit the cache, and, at least as of right now, only nonrelative names can issue diagnostics
1413                // (Since diagnostics are only issued via import or export map lookup)
1414                // This may totally change if/when the issue of output paths not mapping to input files is fixed in a broader context
1415                // When it is, how we extract diagnostics from the module name resolver will have the be refined - the current cache
1416                // APIs wrapping the underlying resolver make it almost impossible to smuggle the diagnostics out in a generalized way
1417                if (isExternalModuleNameRelative(name)) continue;
1418                const diags = moduleResolutionCache.getOrCreateCacheForModuleName(name, mode, redirectedReference).get(containingDir)?.resolutionDiagnostics;
1419                addResolutionDiagnostics(diags);
1420            }
1421        }
1422
1423        function resolveModuleNamesWorker(moduleNames: string[], containingFile: SourceFile, reusedNames: string[] | undefined): readonly ResolvedModuleFull[] {
1424            if (!moduleNames.length) return emptyArray;
1425            const containingFileName = getNormalizedAbsolutePath(containingFile.originalFileName, currentDirectory);
1426            const redirectedReference = getRedirectReferenceForResolution(containingFile);
1427            tracing?.push(tracing.Phase.Program, "resolveModuleNamesWorker", { containingFileName });
1428            performance.mark("beforeResolveModule");
1429            const result = actualResolveModuleNamesWorker(moduleNames, containingFile, containingFileName, reusedNames, redirectedReference);
1430            performance.mark("afterResolveModule");
1431            performance.measure("ResolveModule", "beforeResolveModule", "afterResolveModule");
1432            tracing?.pop();
1433            pullDiagnosticsFromCache(moduleNames, containingFile);
1434            return result;
1435        }
1436
1437        function resolveTypeReferenceDirectiveNamesWorker(typeDirectiveNames: string[] | readonly FileReference[], containingFile: string | SourceFile): readonly (ResolvedTypeReferenceDirective | undefined)[] {
1438            if (!typeDirectiveNames.length) return [];
1439            const containingFileName = !isString(containingFile) ? getNormalizedAbsolutePath(containingFile.originalFileName, currentDirectory) : containingFile;
1440            const redirectedReference = !isString(containingFile) ? getRedirectReferenceForResolution(containingFile) : undefined;
1441            const containingFileMode = !isString(containingFile) ? containingFile.impliedNodeFormat : undefined;
1442            tracing?.push(tracing.Phase.Program, "resolveTypeReferenceDirectiveNamesWorker", { containingFileName });
1443            performance.mark("beforeResolveTypeReference");
1444            const result = actualResolveTypeReferenceDirectiveNamesWorker(typeDirectiveNames, containingFileName, redirectedReference, containingFileMode);
1445            performance.mark("afterResolveTypeReference");
1446            performance.measure("ResolveTypeReference", "beforeResolveTypeReference", "afterResolveTypeReference");
1447            tracing?.pop();
1448            return result;
1449        }
1450
1451        function getRedirectReferenceForResolution(file: SourceFile) {
1452            const redirect = getResolvedProjectReferenceToRedirect(file.originalFileName);
1453            if (redirect || !isDeclarationFileName(file.originalFileName)) return redirect;
1454
1455            // The originalFileName could not be actual source file name if file found was d.ts from referecned project
1456            // 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
1457            const resultFromDts = getRedirectReferenceForResolutionFromSourceOfProject(file.path);
1458            if (resultFromDts) return resultFromDts;
1459
1460            // If preserveSymlinks is true, module resolution wont jump the symlink
1461            // but the resolved real path may be the .d.ts from project reference
1462            // Note:: Currently we try the real path only if the
1463            // file is from node_modules to avoid having to run real path on all file paths
1464            if (!host.realpath || !options.preserveSymlinks || (!stringContains(file.originalFileName, nodeModulesPathPart) && !stringContains(file.originalFileName, ohModulesPathPart))) return undefined;
1465            const realDeclarationPath = toPath(host.realpath(file.originalFileName));
1466            return realDeclarationPath === file.path ? undefined : getRedirectReferenceForResolutionFromSourceOfProject(realDeclarationPath);
1467        }
1468
1469        function getRedirectReferenceForResolutionFromSourceOfProject(filePath: Path) {
1470            const source = getSourceOfProjectReferenceRedirect(filePath);
1471            if (isString(source)) return getResolvedProjectReferenceToRedirect(source);
1472            if (!source) return undefined;
1473            // Output of .d.ts file so return resolved ref that matches the out file name
1474            return forEachResolvedProjectReference(resolvedRef => {
1475                const out = outFile(resolvedRef.commandLine.options);
1476                if (!out) return undefined;
1477                return toPath(out) === filePath ? resolvedRef : undefined;
1478            });
1479        }
1480
1481        function compareDefaultLibFiles(a: SourceFile, b: SourceFile) {
1482            return compareValues(getDefaultLibFilePriority(a), getDefaultLibFilePriority(b));
1483        }
1484
1485        function getDefaultLibFilePriority(a: SourceFile) {
1486            if (containsPath(defaultLibraryPath, a.fileName, /*ignoreCase*/ false)) {
1487                const basename = getBaseFileName(a.fileName);
1488                if (basename === "lib.d.ts" || basename === "lib.es6.d.ts") return 0;
1489                const name = removeSuffix(removePrefix(basename, "lib."), ".d.ts");
1490                const index = libs.indexOf(name);
1491                if (index !== -1) return index + 1;
1492            }
1493            return libs.length + 2;
1494        }
1495
1496        function getResolvedModuleWithFailedLookupLocationsFromCache(moduleName: string, containingFile: string, mode?: ModuleKind.CommonJS | ModuleKind.ESNext): ResolvedModuleWithFailedLookupLocations | undefined {
1497            return moduleResolutionCache && resolveModuleNameFromCache(moduleName, containingFile, moduleResolutionCache, mode);
1498        }
1499
1500        function toPath(fileName: string): Path {
1501            return ts.toPath(fileName, currentDirectory, getCanonicalFileName);
1502        }
1503
1504        function getCommonSourceDirectory() {
1505            if (commonSourceDirectory === undefined) {
1506                const emittedFiles = filter(files, file => sourceFileMayBeEmitted(file, program));
1507                commonSourceDirectory = ts.getCommonSourceDirectory(
1508                    options,
1509                    () => mapDefined(emittedFiles, file => file.isDeclarationFile ? undefined : file.fileName),
1510                    currentDirectory,
1511                    getCanonicalFileName,
1512                    commonSourceDirectory => checkSourceFilesBelongToPath(emittedFiles, commonSourceDirectory)
1513                );
1514            }
1515            return commonSourceDirectory;
1516        }
1517
1518        function getClassifiableNames() {
1519            if (!classifiableNames) {
1520                // Initialize a checker so that all our files are bound.
1521                getTypeChecker();
1522                classifiableNames = new Set();
1523
1524                for (const sourceFile of files) {
1525                    sourceFile.classifiableNames?.forEach(value => classifiableNames.add(value));
1526                }
1527            }
1528
1529            return classifiableNames;
1530        }
1531
1532        function resolveModuleNamesReusingOldState(moduleNames: string[], file: SourceFile): readonly (ResolvedModuleFull | undefined)[] {
1533            if (structureIsReused === StructureIsReused.Not && !file.ambientModuleNames.length) {
1534                // If the old program state does not permit reusing resolutions and `file` does not contain locally defined ambient modules,
1535                // the best we can do is fallback to the default logic.
1536                return resolveModuleNamesWorker(moduleNames, file, /*reusedNames*/ undefined);
1537            }
1538
1539            const oldSourceFile = oldProgram && oldProgram.getSourceFile(file.fileName);
1540            if (oldSourceFile !== file && file.resolvedModules) {
1541                // `file` was created for the new program.
1542                //
1543                // We only set `file.resolvedModules` via work from the current function,
1544                // so it is defined iff we already called the current function on `file`.
1545                // That call happened no later than the creation of the `file` object,
1546                // which per above occurred during the current program creation.
1547                // Since we assume the filesystem does not change during program creation,
1548                // it is safe to reuse resolutions from the earlier call.
1549                const result: (ResolvedModuleFull | undefined)[] = [];
1550                let i = 0;
1551                for (const moduleName of moduleNames) {
1552                    const resolvedModule = file.resolvedModules.get(moduleName, getModeForResolutionAtIndex(file, i));
1553                    i++;
1554                    result.push(resolvedModule);
1555                }
1556                return result;
1557            }
1558            // At this point, we know at least one of the following hold:
1559            // - file has local declarations for ambient modules
1560            // - old program state is available
1561            // With this information, we can infer some module resolutions without performing resolution.
1562
1563            /** An ordered list of module names for which we cannot recover the resolution. */
1564            let unknownModuleNames: string[] | undefined;
1565            /**
1566             * The indexing of elements in this list matches that of `moduleNames`.
1567             *
1568             * Before combining results, result[i] is in one of the following states:
1569             * * undefined: needs to be recomputed,
1570             * * predictedToResolveToAmbientModuleMarker: known to be an ambient module.
1571             * Needs to be reset to undefined before returning,
1572             * * ResolvedModuleFull instance: can be reused.
1573             */
1574            let result: (ResolvedModuleFull | undefined)[] | undefined;
1575            let reusedNames: string[] | undefined;
1576            /** A transient placeholder used to mark predicted resolution in the result list. */
1577            const predictedToResolveToAmbientModuleMarker: ResolvedModuleFull = {} as any;
1578
1579            for (let i = 0; i < moduleNames.length; i++) {
1580                const moduleName = moduleNames[i];
1581                // If the source file is unchanged and doesnt have invalidated resolution, reuse the module resolutions
1582                if (file === oldSourceFile && !hasInvalidatedResolutions(oldSourceFile.path)) {
1583                    const oldResolvedModule = getResolvedModule(oldSourceFile, moduleName, getModeForResolutionAtIndex(oldSourceFile, i));
1584                    if (oldResolvedModule) {
1585                        if (isTraceEnabled(options, host)) {
1586                            trace(host,
1587                                oldResolvedModule.packageId ?
1588                                    Diagnostics.Reusing_resolution_of_module_0_from_1_of_old_program_it_was_successfully_resolved_to_2_with_Package_ID_3 :
1589                                    Diagnostics.Reusing_resolution_of_module_0_from_1_of_old_program_it_was_successfully_resolved_to_2,
1590                                moduleName,
1591                                getNormalizedAbsolutePath(file.originalFileName, currentDirectory),
1592                                oldResolvedModule.resolvedFileName,
1593                                oldResolvedModule.packageId && packageIdToString(oldResolvedModule.packageId)
1594                            );
1595                        }
1596                        (result || (result = new Array(moduleNames.length)))[i] = oldResolvedModule;
1597                        (reusedNames || (reusedNames = [])).push(moduleName);
1598                        continue;
1599                    }
1600                }
1601                // We know moduleName resolves to an ambient module provided that moduleName:
1602                // - is in the list of ambient modules locally declared in the current source file.
1603                // - resolved to an ambient module in the old program whose declaration is in an unmodified file
1604                //   (so the same module declaration will land in the new program)
1605                let resolvesToAmbientModuleInNonModifiedFile = false;
1606                if (contains(file.ambientModuleNames, moduleName)) {
1607                    resolvesToAmbientModuleInNonModifiedFile = true;
1608                    if (isTraceEnabled(options, host)) {
1609                        trace(host, Diagnostics.Module_0_was_resolved_as_locally_declared_ambient_module_in_file_1, moduleName, getNormalizedAbsolutePath(file.originalFileName, currentDirectory));
1610                    }
1611                }
1612                else {
1613                    resolvesToAmbientModuleInNonModifiedFile = moduleNameResolvesToAmbientModuleInNonModifiedFile(moduleName, i);
1614                }
1615
1616                if (resolvesToAmbientModuleInNonModifiedFile) {
1617                    (result || (result = new Array(moduleNames.length)))[i] = predictedToResolveToAmbientModuleMarker;
1618                }
1619                else {
1620                    // Resolution failed in the old program, or resolved to an ambient module for which we can't reuse the result.
1621                    (unknownModuleNames || (unknownModuleNames = [])).push(moduleName);
1622                }
1623            }
1624
1625            const resolutions = unknownModuleNames && unknownModuleNames.length
1626                ? resolveModuleNamesWorker(unknownModuleNames, file, reusedNames)
1627                : emptyArray;
1628
1629            // Combine results of resolutions and predicted results
1630            if (!result) {
1631                // There were no unresolved/ambient resolutions.
1632                Debug.assert(resolutions.length === moduleNames.length);
1633                return resolutions;
1634            }
1635
1636            let j = 0;
1637            for (let i = 0; i < result.length; i++) {
1638                if (result[i]) {
1639                    // `result[i]` is either a `ResolvedModuleFull` or a marker.
1640                    // If it is the former, we can leave it as is.
1641                    if (result[i] === predictedToResolveToAmbientModuleMarker) {
1642                        result[i] = undefined;
1643                    }
1644                }
1645                else {
1646                    result[i] = resolutions[j];
1647                    j++;
1648                }
1649            }
1650            Debug.assert(j === resolutions.length);
1651
1652            return result;
1653
1654            // If we change our policy of rechecking failed lookups on each program create,
1655            // we should adjust the value returned here.
1656            function moduleNameResolvesToAmbientModuleInNonModifiedFile(moduleName: string, index: number): boolean {
1657                if (index >= length(oldSourceFile?.imports) + length(oldSourceFile?.moduleAugmentations)) return false; // mode index out of bounds, don't reuse resolution
1658                const resolutionToFile = getResolvedModule(oldSourceFile, moduleName, oldSourceFile && getModeForResolutionAtIndex(oldSourceFile, index));
1659                const resolvedFile = resolutionToFile && oldProgram!.getSourceFile(resolutionToFile.resolvedFileName);
1660                if (resolutionToFile && resolvedFile) {
1661                    // In the old program, we resolved to an ambient module that was in the same
1662                    //   place as we expected to find an actual module file.
1663                    // We actually need to return 'false' here even though this seems like a 'true' case
1664                    //   because the normal module resolution algorithm will find this anyway.
1665                    return false;
1666                }
1667
1668                // at least one of declarations should come from non-modified source file
1669                const unmodifiedFile = ambientModuleNameToUnmodifiedFileName.get(moduleName);
1670
1671                if (!unmodifiedFile) {
1672                    return false;
1673                }
1674
1675                if (isTraceEnabled(options, host)) {
1676                    trace(host, Diagnostics.Module_0_was_resolved_as_ambient_module_declared_in_1_since_this_file_was_not_modified, moduleName, unmodifiedFile);
1677                }
1678                return true;
1679            }
1680        }
1681
1682        function canReuseProjectReferences(): boolean {
1683            return !forEachProjectReference(
1684                oldProgram!.getProjectReferences(),
1685                oldProgram!.getResolvedProjectReferences(),
1686                (oldResolvedRef, parent, index) => {
1687                    const newRef = (parent ? parent.commandLine.projectReferences : projectReferences)![index];
1688                    const newResolvedRef = parseProjectReferenceConfigFile(newRef);
1689                    if (oldResolvedRef) {
1690                        // Resolved project reference has gone missing or changed
1691                        return !newResolvedRef ||
1692                            newResolvedRef.sourceFile !== oldResolvedRef.sourceFile ||
1693                            !arrayIsEqualTo(oldResolvedRef.commandLine.fileNames, newResolvedRef.commandLine.fileNames);
1694                    }
1695                    else {
1696                        // A previously-unresolved reference may be resolved now
1697                        return newResolvedRef !== undefined;
1698                    }
1699                },
1700                (oldProjectReferences, parent) => {
1701                    // If array of references is changed, we cant resue old program
1702                    const newReferences = parent ? getResolvedProjectReferenceByPath(parent.sourceFile.path)!.commandLine.projectReferences : projectReferences;
1703                    return !arrayIsEqualTo(oldProjectReferences, newReferences, projectReferenceIsEqualTo);
1704                }
1705            );
1706        }
1707
1708        function tryReuseStructureFromOldProgram(): StructureIsReused {
1709            if (!oldProgram) {
1710                return StructureIsReused.Not;
1711            }
1712
1713            // check properties that can affect structure of the program or module resolution strategy
1714            // if any of these properties has changed - structure cannot be reused
1715            const oldOptions = oldProgram.getCompilerOptions();
1716            if (changesAffectModuleResolution(oldOptions, options)) {
1717                return StructureIsReused.Not;
1718            }
1719
1720            // there is an old program, check if we can reuse its structure
1721            const oldRootNames = oldProgram.getRootFileNames();
1722            if (!arrayIsEqualTo(oldRootNames, rootNames)) {
1723                return StructureIsReused.Not;
1724            }
1725
1726            // Check if any referenced project tsconfig files are different
1727            if (!canReuseProjectReferences()) {
1728                return StructureIsReused.Not;
1729            }
1730            if (projectReferences) {
1731                resolvedProjectReferences = projectReferences.map(parseProjectReferenceConfigFile);
1732            }
1733
1734            // check if program source files has changed in the way that can affect structure of the program
1735            const newSourceFiles: SourceFile[] = [];
1736            const modifiedSourceFiles: { oldFile: SourceFile, newFile: SourceFile }[] = [];
1737            structureIsReused = StructureIsReused.Completely;
1738
1739            // If the missing file paths are now present, it can change the progam structure,
1740            // and hence cant reuse the structure.
1741            // This is same as how we dont reuse the structure if one of the file from old program is now missing
1742            if (oldProgram.getMissingFilePaths().some(missingFilePath => host.fileExists(missingFilePath))) {
1743                return StructureIsReused.Not;
1744            }
1745
1746            const oldSourceFiles = oldProgram.getSourceFiles();
1747            const enum SeenPackageName { Exists, Modified }
1748            const seenPackageNames = new Map<string, SeenPackageName>();
1749
1750            for (const oldSourceFile of oldSourceFiles) {
1751                const sourceFileOptions = getCreateSourceFileOptions(oldSourceFile.fileName, moduleResolutionCache, host, options);
1752                let newSourceFile = host.getSourceFileByPath
1753                    ? host.getSourceFileByPath(oldSourceFile.fileName, oldSourceFile.resolvedPath, sourceFileOptions, /*onError*/ undefined, shouldCreateNewSourceFile || sourceFileOptions.impliedNodeFormat !== oldSourceFile.impliedNodeFormat)
1754                    : host.getSourceFile(oldSourceFile.fileName, sourceFileOptions, /*onError*/ undefined, shouldCreateNewSourceFile || sourceFileOptions.impliedNodeFormat !== oldSourceFile.impliedNodeFormat); // TODO: GH#18217
1755
1756                if (!newSourceFile) {
1757                    return StructureIsReused.Not;
1758                }
1759                newSourceFile.packageJsonLocations = sourceFileOptions.packageJsonLocations?.length ? sourceFileOptions.packageJsonLocations : undefined;
1760                newSourceFile.packageJsonScope = sourceFileOptions.packageJsonScope;
1761
1762                Debug.assert(!newSourceFile.redirectInfo, "Host should not return a redirect source file from `getSourceFile`");
1763
1764                let fileChanged: boolean;
1765                if (oldSourceFile.redirectInfo) {
1766                    // We got `newSourceFile` by path, so it is actually for the unredirected file.
1767                    // This lets us know if the unredirected file has changed. If it has we should break the redirect.
1768                    if (newSourceFile !== oldSourceFile.redirectInfo.unredirected) {
1769                        // Underlying file has changed. Might not redirect anymore. Must rebuild program.
1770                        return StructureIsReused.Not;
1771                    }
1772                    fileChanged = false;
1773                    newSourceFile = oldSourceFile; // Use the redirect.
1774                }
1775                else if (oldProgram.redirectTargetsMap.has(oldSourceFile.path)) {
1776                    // If a redirected-to source file changes, the redirect may be broken.
1777                    if (newSourceFile !== oldSourceFile) {
1778                        return StructureIsReused.Not;
1779                    }
1780                    fileChanged = false;
1781                }
1782                else {
1783                    fileChanged = newSourceFile !== oldSourceFile;
1784                }
1785
1786                // Since the project references havent changed, its right to set originalFileName and resolvedPath here
1787                newSourceFile.path = oldSourceFile.path;
1788                newSourceFile.originalFileName = oldSourceFile.originalFileName;
1789                newSourceFile.resolvedPath = oldSourceFile.resolvedPath;
1790                newSourceFile.fileName = oldSourceFile.fileName;
1791
1792                const packageName = oldProgram.sourceFileToPackageName.get(oldSourceFile.path);
1793                if (packageName !== undefined) {
1794                    // If there are 2 different source files for the same package name and at least one of them changes,
1795                    // they might become redirects. So we must rebuild the program.
1796                    const prevKind = seenPackageNames.get(packageName);
1797                    const newKind = fileChanged ? SeenPackageName.Modified : SeenPackageName.Exists;
1798                    if ((prevKind !== undefined && newKind === SeenPackageName.Modified) || prevKind === SeenPackageName.Modified) {
1799                        return StructureIsReused.Not;
1800                    }
1801                    seenPackageNames.set(packageName, newKind);
1802                }
1803
1804                if (fileChanged) {
1805                    if (oldSourceFile.impliedNodeFormat !== newSourceFile.impliedNodeFormat) {
1806                        structureIsReused = StructureIsReused.SafeModules;
1807                    }
1808                    // The `newSourceFile` object was created for the new program.
1809                    else if (!arrayIsEqualTo(oldSourceFile.libReferenceDirectives, newSourceFile.libReferenceDirectives, fileReferenceIsEqualTo)) {
1810                        // 'lib' references has changed. Matches behavior in changesAffectModuleResolution
1811                        structureIsReused = StructureIsReused.SafeModules;
1812                    }
1813                    else if (oldSourceFile.hasNoDefaultLib !== newSourceFile.hasNoDefaultLib) {
1814                        // value of no-default-lib has changed
1815                        // this will affect if default library is injected into the list of files
1816                        structureIsReused = StructureIsReused.SafeModules;
1817                    }
1818                    // check tripleslash references
1819                    else if (!arrayIsEqualTo(oldSourceFile.referencedFiles, newSourceFile.referencedFiles, fileReferenceIsEqualTo)) {
1820                        // tripleslash references has changed
1821                        structureIsReused = StructureIsReused.SafeModules;
1822                    }
1823                    else {
1824                        // check imports and module augmentations
1825                        collectExternalModuleReferences(newSourceFile);
1826                        if (!arrayIsEqualTo(oldSourceFile.imports, newSourceFile.imports, moduleNameIsEqualTo)) {
1827                            // imports has changed
1828                            structureIsReused = StructureIsReused.SafeModules;
1829                        }
1830                        else if (!arrayIsEqualTo(oldSourceFile.moduleAugmentations, newSourceFile.moduleAugmentations, moduleNameIsEqualTo)) {
1831                            // moduleAugmentations has changed
1832                            structureIsReused = StructureIsReused.SafeModules;
1833                        }
1834                        else if ((oldSourceFile.flags & NodeFlags.PermanentlySetIncrementalFlags) !== (newSourceFile.flags & NodeFlags.PermanentlySetIncrementalFlags)) {
1835                            // dynamicImport has changed
1836                            structureIsReused = StructureIsReused.SafeModules;
1837                        }
1838                        else if (!arrayIsEqualTo(oldSourceFile.typeReferenceDirectives, newSourceFile.typeReferenceDirectives, fileReferenceIsEqualTo)) {
1839                            // 'types' references has changed
1840                            structureIsReused = StructureIsReused.SafeModules;
1841                        }
1842                    }
1843
1844                    // tentatively approve the file
1845                    modifiedSourceFiles.push({ oldFile: oldSourceFile, newFile: newSourceFile });
1846                }
1847                else if (hasInvalidatedResolutions(oldSourceFile.path)) {
1848                    // 'module/types' references could have changed
1849                    structureIsReused = StructureIsReused.SafeModules;
1850
1851                    // add file to the modified list so that we will resolve it later
1852                    modifiedSourceFiles.push({ oldFile: oldSourceFile, newFile: newSourceFile });
1853                }
1854
1855                // if file has passed all checks it should be safe to reuse it
1856                newSourceFiles.push(newSourceFile);
1857            }
1858
1859            if (structureIsReused !== StructureIsReused.Completely) {
1860                return structureIsReused;
1861            }
1862
1863            const modifiedFiles = modifiedSourceFiles.map(f => f.oldFile);
1864            for (const oldFile of oldSourceFiles) {
1865                if (!contains(modifiedFiles, oldFile)) {
1866                    for (const moduleName of oldFile.ambientModuleNames) {
1867                        ambientModuleNameToUnmodifiedFileName.set(moduleName, oldFile.fileName);
1868                    }
1869                }
1870            }
1871            // try to verify results of module resolution
1872            for (const { oldFile: oldSourceFile, newFile: newSourceFile } of modifiedSourceFiles) {
1873                const moduleNames = getModuleNames(newSourceFile);
1874                const resolutions = resolveModuleNamesReusingOldState(moduleNames, newSourceFile);
1875                // ensure that module resolution results are still correct
1876                const resolutionsChanged = hasChangesInResolutions(moduleNames, resolutions, oldSourceFile.resolvedModules, oldSourceFile, moduleResolutionIsEqualTo);
1877                if (resolutionsChanged) {
1878                    structureIsReused = StructureIsReused.SafeModules;
1879                    newSourceFile.resolvedModules = zipToModeAwareCache(newSourceFile, moduleNames, resolutions);
1880                }
1881                else {
1882                    newSourceFile.resolvedModules = oldSourceFile.resolvedModules;
1883                }
1884                const typesReferenceDirectives = newSourceFile.typeReferenceDirectives;
1885                const typeReferenceResolutions = resolveTypeReferenceDirectiveNamesWorker(typesReferenceDirectives, newSourceFile);
1886                // ensure that types resolutions are still correct
1887                const typeReferenceResolutionsChanged = hasChangesInResolutions(typesReferenceDirectives, typeReferenceResolutions, oldSourceFile.resolvedTypeReferenceDirectiveNames, oldSourceFile, typeDirectiveIsEqualTo);
1888                if (typeReferenceResolutionsChanged) {
1889                    structureIsReused = StructureIsReused.SafeModules;
1890                    newSourceFile.resolvedTypeReferenceDirectiveNames = zipToModeAwareCache(newSourceFile, typesReferenceDirectives, typeReferenceResolutions);
1891                }
1892                else {
1893                    newSourceFile.resolvedTypeReferenceDirectiveNames = oldSourceFile.resolvedTypeReferenceDirectiveNames;
1894                }
1895            }
1896
1897            if (structureIsReused !== StructureIsReused.Completely) {
1898                return structureIsReused;
1899            }
1900
1901            if (changesAffectingProgramStructure(oldOptions, options) || host.hasChangedAutomaticTypeDirectiveNames?.()) {
1902                return StructureIsReused.SafeModules;
1903            }
1904
1905            missingFilePaths = oldProgram.getMissingFilePaths();
1906
1907            // update fileName -> file mapping
1908            Debug.assert(newSourceFiles.length === oldProgram.getSourceFiles().length);
1909            for (const newSourceFile of newSourceFiles) {
1910                filesByName.set(newSourceFile.path, newSourceFile);
1911            }
1912            const oldFilesByNameMap = oldProgram.getFilesByNameMap();
1913            oldFilesByNameMap.forEach((oldFile, path) => {
1914                if (!oldFile) {
1915                    filesByName.set(path, oldFile);
1916                    return;
1917                }
1918                if (oldFile.path === path) {
1919                    // Set the file as found during node modules search if it was found that way in old progra,
1920                    if (oldProgram!.isSourceFileFromExternalLibrary(oldFile)) {
1921                        sourceFilesFoundSearchingNodeModules.set(oldFile.path, true);
1922                    }
1923                    return;
1924                }
1925                filesByName.set(path, filesByName.get(oldFile.path));
1926            });
1927
1928            files = newSourceFiles;
1929            fileReasons = oldProgram.getFileIncludeReasons();
1930            fileProcessingDiagnostics = oldProgram.getFileProcessingDiagnostics();
1931            resolvedTypeReferenceDirectives = oldProgram.getResolvedTypeReferenceDirectives();
1932
1933            sourceFileToPackageName = oldProgram.sourceFileToPackageName;
1934            redirectTargetsMap = oldProgram.redirectTargetsMap;
1935            usesUriStyleNodeCoreModules = oldProgram.usesUriStyleNodeCoreModules;
1936
1937            return StructureIsReused.Completely;
1938        }
1939
1940        function getEmitHost(writeFileCallback?: WriteFileCallback): EmitHost {
1941            return {
1942                getPrependNodes,
1943                getCanonicalFileName,
1944                getCommonSourceDirectory: program.getCommonSourceDirectory,
1945                getCompilerOptions: program.getCompilerOptions,
1946                getCurrentDirectory: () => currentDirectory,
1947                getNewLine: () => host.getNewLine(),
1948                getSourceFile: program.getSourceFile,
1949                getSourceFileByPath: program.getSourceFileByPath,
1950                getSourceFiles: program.getSourceFiles,
1951                getLibFileFromReference: program.getLibFileFromReference,
1952                isSourceFileFromExternalLibrary,
1953                getResolvedProjectReferenceToRedirect,
1954                getProjectReferenceRedirect,
1955                isSourceOfProjectReferenceRedirect,
1956                getSymlinkCache,
1957                writeFile: writeFileCallback || writeFile,
1958                isEmitBlocked,
1959                readFile: f => host.readFile(f),
1960                fileExists: f => {
1961                    // Use local caches
1962                    const path = toPath(f);
1963                    if (getSourceFileByPath(path)) return true;
1964                    if (contains(missingFilePaths, path)) return false;
1965                    // Before falling back to the host
1966                    return host.fileExists(f);
1967                },
1968                useCaseSensitiveFileNames: () => host.useCaseSensitiveFileNames(),
1969                getProgramBuildInfo: () => program.getProgramBuildInfo && program.getProgramBuildInfo(),
1970                getSourceFileFromReference: (file, ref) => program.getSourceFileFromReference(file, ref),
1971                redirectTargetsMap,
1972                getFileIncludeReasons: program.getFileIncludeReasons,
1973                createHash: maybeBind(host, host.createHash),
1974                getProgramBuildInfoForLinter: () => program.getProgramBuildInfoForLinter && program.getProgramBuildInfoForLinter(),
1975            };
1976        }
1977
1978        function writeFile(
1979            fileName: string,
1980            text: string,
1981            writeByteOrderMark: boolean,
1982            onError?: (message: string) => void,
1983            sourceFiles?: readonly SourceFile[],
1984            data?: WriteFileCallbackData
1985        ) {
1986            host.writeFile(fileName, text, writeByteOrderMark, onError, sourceFiles, data);
1987        }
1988
1989        function emitBuildInfo(writeFileCallback?: WriteFileCallback): EmitResult {
1990            Debug.assert(!outFile(options));
1991            tracing?.push(tracing.Phase.Emit, "emitBuildInfo", {}, /*separateBeginAndEnd*/ true);
1992            performance.mark("beforeEmit");
1993            const emitResult = emitFiles(
1994                notImplementedResolver,
1995                getEmitHost(writeFileCallback),
1996                /*targetSourceFile*/ undefined,
1997                /*transformers*/ noTransformers,
1998                /*emitOnlyDtsFiles*/ false,
1999                /*onlyBuildInfo*/ true
2000            );
2001
2002            performance.mark("afterEmit");
2003            performance.measure("Emit", "beforeEmit", "afterEmit");
2004            tracing?.pop();
2005            return emitResult;
2006        }
2007
2008        function getResolvedProjectReferences() {
2009            return resolvedProjectReferences;
2010        }
2011
2012        function getProjectReferences() {
2013            return projectReferences;
2014        }
2015
2016        function getPrependNodes() {
2017            return createPrependNodes(
2018                projectReferences,
2019                (_ref, index) => resolvedProjectReferences![index]?.commandLine,
2020                fileName => {
2021                    const path = toPath(fileName);
2022                    const sourceFile = getSourceFileByPath(path);
2023                    return sourceFile ? sourceFile.text : filesByName.has(path) ? undefined : host.readFile(path);
2024                }
2025            );
2026        }
2027
2028        function isSourceFileFromExternalLibrary(file: SourceFile): boolean {
2029            return !!sourceFilesFoundSearchingNodeModules.get(file.path);
2030        }
2031
2032        function isSourceFileDefaultLibrary(file: SourceFile): boolean {
2033            if (!file.isDeclarationFile) {
2034                return false;
2035            }
2036
2037            if (file.hasNoDefaultLib) {
2038                return true;
2039            }
2040
2041            if (!options.noLib) {
2042                return false;
2043            }
2044
2045            // If '--lib' is not specified, include default library file according to '--target'
2046            // otherwise, using options specified in '--lib' instead of '--target' default library file
2047            const equalityComparer = host.useCaseSensitiveFileNames() ? equateStringsCaseSensitive : equateStringsCaseInsensitive;
2048            if (!options.lib) {
2049                return equalityComparer(file.fileName, getDefaultLibraryFileName());
2050            }
2051            else {
2052                return some(options.lib, libFileName => equalityComparer(file.fileName, pathForLibFile(libFileName)));
2053            }
2054        }
2055
2056        function getEtsLibSFromProgram() {
2057            return getEtsLibs(program);
2058        }
2059
2060        function getTypeChecker() {
2061            return typeChecker || (typeChecker = createTypeChecker(program));
2062        }
2063
2064        function getLinterTypeChecker() {
2065            return linterTypeChecker || (linterTypeChecker = createTypeChecker(program, true));
2066        }
2067
2068        function emit(sourceFile?: SourceFile, writeFileCallback?: WriteFileCallback, cancellationToken?: CancellationToken, emitOnlyDtsFiles?: boolean, transformers?: CustomTransformers, forceDtsEmit?: boolean): EmitResult {
2069            tracing?.push(tracing.Phase.Emit, "emit", { path: sourceFile?.path }, /*separateBeginAndEnd*/ true);
2070            const result = runWithCancellationToken(() => emitWorker(program, sourceFile, writeFileCallback, cancellationToken, emitOnlyDtsFiles, transformers, forceDtsEmit));
2071            tracing?.pop();
2072            return result;
2073        }
2074
2075        function isEmitBlocked(emitFileName: string): boolean {
2076            return hasEmitBlockingDiagnostics.has(toPath(emitFileName));
2077        }
2078
2079        function emitWorker(program: Program, sourceFile: SourceFile | undefined, writeFileCallback: WriteFileCallback | undefined, cancellationToken: CancellationToken | undefined, emitOnlyDtsFiles?: boolean, customTransformers?: CustomTransformers, forceDtsEmit?: boolean): EmitResult {
2080            if (!forceDtsEmit) {
2081                const result = handleNoEmitOptions(program, sourceFile, writeFileCallback, cancellationToken);
2082                if (result) return result;
2083            }
2084
2085            // Create the emit resolver outside of the "emitTime" tracking code below.  That way
2086            // any cost associated with it (like type checking) are appropriate associated with
2087            // the type-checking counter.
2088            //
2089            // If the -out option is specified, we should not pass the source file to getEmitResolver.
2090            // This is because in the -out scenario all files need to be emitted, and therefore all
2091            // files need to be type checked. And the way to specify that all files need to be type
2092            // checked is to not pass the file to getEmitResolver.
2093            const emitResolver = getTypeChecker().getEmitResolver(outFile(options) ? undefined : sourceFile, cancellationToken);
2094
2095            performance.mark("beforeEmit");
2096
2097            const emitResult = emitFiles(
2098                emitResolver,
2099                getEmitHost(writeFileCallback),
2100                sourceFile,
2101                getTransformers(options, customTransformers, emitOnlyDtsFiles),
2102                emitOnlyDtsFiles,
2103                /*onlyBuildInfo*/ false,
2104                forceDtsEmit
2105            );
2106
2107            performance.mark("afterEmit");
2108            performance.measure("Emit", "beforeEmit", "afterEmit");
2109            return emitResult;
2110        }
2111
2112        function getSourceFile(fileName: string): SourceFile | undefined {
2113            return getSourceFileByPath(toPath(fileName));
2114        }
2115
2116        function getSourceFileByPath(path: Path): SourceFile | undefined {
2117            return filesByName.get(path) || undefined;
2118        }
2119
2120        function getDiagnosticsHelper<T extends Diagnostic>(
2121            sourceFile: SourceFile | undefined,
2122            getDiagnostics: (sourceFile: SourceFile, cancellationToken: CancellationToken | undefined) => readonly T[],
2123            cancellationToken: CancellationToken | undefined): readonly T[] {
2124            if (sourceFile) {
2125                return getDiagnostics(sourceFile, cancellationToken);
2126            }
2127            return sortAndDeduplicateDiagnostics(flatMap(program.getSourceFiles(), sourceFile => {
2128                if (cancellationToken) {
2129                    cancellationToken.throwIfCancellationRequested();
2130                }
2131                return getDiagnostics(sourceFile, cancellationToken);
2132            }));
2133        }
2134
2135        function getSyntacticDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): readonly DiagnosticWithLocation[] {
2136            return getDiagnosticsHelper(sourceFile, getSyntacticDiagnosticsForFile, cancellationToken);
2137        }
2138
2139        function getSemanticDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): readonly Diagnostic[] {
2140            return getDiagnosticsHelper(sourceFile, getSemanticDiagnosticsForFile, cancellationToken);
2141        }
2142
2143        function getSemanticDiagnosticsForLinter(sourceFile?: SourceFile, cancellationToken?: CancellationToken): readonly Diagnostic[] {
2144            return getDiagnosticsHelper(sourceFile, getSemanticDiagnosticsForFileForLinter, cancellationToken);
2145        }
2146
2147        function getSemanticDiagnosticsForFileForLinter(sourceFile: SourceFile, cancellationToken: CancellationToken | undefined): readonly Diagnostic[] {
2148            return concatenate(
2149                filterSemanticDiagnostics(getBindAndCheckDiagnosticsForFile(sourceFile, cancellationToken, true), options),
2150                getProgramDiagnostics(sourceFile)
2151            );
2152        }
2153
2154        function getCachedSemanticDiagnostics(sourceFile?: SourceFile): readonly Diagnostic[] | undefined {
2155           return sourceFile
2156                ? cachedBindAndCheckDiagnosticsForFile.perFile?.get(sourceFile.path)
2157                : cachedBindAndCheckDiagnosticsForFile.allDiagnostics;
2158        }
2159
2160        function getBindAndCheckDiagnostics(sourceFile: SourceFile, cancellationToken?: CancellationToken, isForLinter?: boolean): readonly Diagnostic[] {
2161            return getBindAndCheckDiagnosticsForFile(sourceFile, cancellationToken, isForLinter);
2162        }
2163
2164        function getProgramDiagnostics(sourceFile: SourceFile): readonly Diagnostic[] {
2165            if (skipTypeChecking(sourceFile, options, program) || (sourceFile.isDeclarationFile && !!options.needDoArkTsLinter)) {
2166                return emptyArray;
2167            }
2168
2169            const programDiagnosticsInFile = programDiagnostics.getDiagnostics(sourceFile.fileName);
2170            if (!sourceFile.commentDirectives?.length) {
2171                return programDiagnosticsInFile;
2172            }
2173
2174            return getDiagnosticsWithPrecedingDirectives(sourceFile, sourceFile.commentDirectives, programDiagnosticsInFile).diagnostics;
2175        }
2176
2177        function getDeclarationDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): readonly DiagnosticWithLocation[] {
2178            const options = program.getCompilerOptions();
2179            // collect diagnostics from the program only once if either no source file was specified or out/outFile is set (bundled emit)
2180            if (!sourceFile || outFile(options)) {
2181                return getDeclarationDiagnosticsWorker(sourceFile, cancellationToken);
2182            }
2183            else {
2184                return getDiagnosticsHelper(sourceFile, getDeclarationDiagnosticsForFile, cancellationToken);
2185            }
2186        }
2187
2188        function getSyntacticDiagnosticsForFile(sourceFile: SourceFile): readonly DiagnosticWithLocation[] {
2189            // For JavaScript files, we report semantic errors for using TypeScript-only
2190            // constructs from within a JavaScript file as syntactic errors.
2191            if (isSourceFileJS(sourceFile)) {
2192                if (!sourceFile.additionalSyntacticDiagnostics) {
2193                    sourceFile.additionalSyntacticDiagnostics = getJSSyntacticDiagnosticsForFile(sourceFile);
2194                }
2195                return concatenate(sourceFile.additionalSyntacticDiagnostics, sourceFile.parseDiagnostics);
2196            }
2197            return sourceFile.parseDiagnostics;
2198        }
2199
2200        function runWithCancellationToken<T>(func: () => T): T {
2201            try {
2202                return func();
2203            }
2204            catch (e) {
2205                if (e instanceof OperationCanceledException) {
2206                    // We were canceled while performing the operation.  Because our type checker
2207                    // might be a bad state, we need to throw it away.
2208                    typeChecker = undefined!;
2209                }
2210
2211                throw e;
2212            }
2213        }
2214
2215        function getSemanticDiagnosticsForFile(sourceFile: SourceFile, cancellationToken: CancellationToken | undefined): readonly Diagnostic[] {
2216            return concatenate(
2217                filterSemanticDiagnostics(getBindAndCheckDiagnosticsForFile(sourceFile, cancellationToken), options),
2218                getProgramDiagnostics(sourceFile)
2219            );
2220        }
2221
2222        function getBindAndCheckDiagnosticsForFile(sourceFile: SourceFile, cancellationToken: CancellationToken | undefined,
2223            isForLinter: boolean = false): readonly Diagnostic[] {
2224            if (!isForLinter) {
2225                return getAndCacheDiagnostics(sourceFile, cancellationToken, cachedBindAndCheckDiagnosticsForFile, getBindAndCheckDiagnosticsForFileNoCache);
2226            }
2227            return getAndCacheDiagnostics(sourceFile, cancellationToken, cachedBindAndCheckDiagnosticsForFileForLinter,
2228                getBindAndCheckDiagnosticsForFileNoCache, true);
2229        }
2230
2231        function getBindAndCheckDiagnosticsForFileNoCache(sourceFile: SourceFile, cancellationToken: CancellationToken | undefined,
2232            isForLinter: boolean = false): readonly Diagnostic[] {
2233            return runWithCancellationToken(() => {
2234                // Only check and block .d.ts import .ets behavior when it is called by "ets-loader" and scanned.
2235                const filterFlag = !!options.needDoArkTsLinter;
2236
2237                if (filterFlag) {
2238                    options.skipLibCheck = false;
2239                }
2240
2241                if (skipTypeChecking(sourceFile, options, program)) {
2242                    return emptyArray;
2243                }
2244
2245                const typeChecker = isForLinter ? getLinterTypeChecker() : getTypeChecker();
2246
2247                Debug.assert(!!sourceFile.bindDiagnostics);
2248
2249                const isJs = sourceFile.scriptKind === ScriptKind.JS || sourceFile.scriptKind === ScriptKind.JSX;
2250                const isCheckJs = isJs && isCheckJsEnabledForFile(sourceFile, options);
2251                const isPlainJs = isPlainJsFile(sourceFile, options.checkJs);
2252                const isTsNoCheck = !!sourceFile.checkJsDirective && sourceFile.checkJsDirective.enabled === false;
2253
2254                // By default, only type-check .ts, .tsx, Deferred, plain JS, checked JS and External
2255                // - plain JS: .js files with no // ts-check and checkJs: undefined
2256                // - check JS: .js files with either // ts-check or checkJs: true
2257                // - external: files that are added by plugins
2258                const includeBindAndCheckDiagnostics = !isTsNoCheck && (sourceFile.scriptKind === ScriptKind.TS || sourceFile.scriptKind === ScriptKind.TSX
2259                        || sourceFile.scriptKind === ScriptKind.External || isPlainJs || isCheckJs || sourceFile.scriptKind === ScriptKind.Deferred || sourceFile.scriptKind === ScriptKind.ETS);
2260                let bindDiagnostics: readonly Diagnostic[] = includeBindAndCheckDiagnostics ? sourceFile.bindDiagnostics : emptyArray;
2261                let checkDiagnostics = includeBindAndCheckDiagnostics ? typeChecker.getDiagnostics(sourceFile, cancellationToken) : emptyArray;
2262                if (isPlainJs) {
2263                    bindDiagnostics = filter(bindDiagnostics, d => plainJSErrors.has(d.code));
2264                    checkDiagnostics = filter(checkDiagnostics, d => plainJSErrors.has(d.code));
2265                }
2266                // skip ts-expect-error errors in plain JS files, and skip JSDoc errors except in checked JS
2267                return getMergedBindAndCheckDiagnostics(sourceFile, includeBindAndCheckDiagnostics && !isPlainJs, bindDiagnostics,
2268                    filterFlag ? filterDiagnostics(checkDiagnostics) : checkDiagnostics, isCheckJs ? sourceFile.jsDocDiagnostics : undefined);
2269            });
2270        }
2271
2272        function filterDiagnostics(allDiagnostics: (readonly Diagnostic[] | undefined)): readonly Diagnostic[] | undefined {
2273            if (allDiagnostics) {
2274                const diagnosticsAfterFilter = allDiagnostics.filter((item) => {
2275                    /* Diagnostics suppression scheme:
2276                     *   1.if `file` comes from `oh_modules`:
2277                     *        skip all the diagnostics in declaration files and importing ArkTS errors from TS files
2278                     *        done.
2279                     *   2.if `file` is a d.ts:
2280                     *        if d.ts is a kit declaration which being named with `@kit.` prefix:
2281                     *            skip all the diagnostics.
2282                     *        else:
2283                     *            skip all the diagnostics other than forbidden imports.
2284                     *        done.
2285                     */
2286                    const isOhModule = (item.file !== undefined) && (normalizePath(item.file.fileName).indexOf("/oh_modules/") !== -1);
2287                    const isNotForbiddenImportDiag = item.messageText !== (options.isCompatibleVersion ?
2288                        Diagnostics.Importing_ArkTS_files_in_JS_and_TS_files_is_about_to_be_forbidden.message :
2289                        Diagnostics.Importing_ArkTS_files_in_JS_and_TS_files_is_forbidden.message);
2290
2291                    if (isOhModule) {
2292                        if (options.skipTscOhModuleCheck) {
2293                            return false;
2294                        }
2295                        if (item.file?.isDeclarationFile) {
2296                            return false;
2297                        }
2298                        return isNotForbiddenImportDiag;
2299                    }
2300
2301                    if (item.file?.scriptKind === ScriptKind.TS && item.file?.isDeclarationFile) {
2302                        if (item.file !== undefined && getBaseFileName(item.file.fileName).indexOf('@kit.') === 0) {
2303                            // kit declaration
2304                            return false;
2305                        }
2306                        return !isNotForbiddenImportDiag;
2307                    }
2308                    return true;
2309                });
2310                return diagnosticsAfterFilter;
2311            }
2312            return emptyArray;
2313        }
2314
2315        function getMergedBindAndCheckDiagnostics(sourceFile: SourceFile, includeBindAndCheckDiagnostics: boolean, ...allDiagnostics: (readonly Diagnostic[] | undefined)[]) {
2316            const flatDiagnostics = flatten(allDiagnostics);
2317            if (!includeBindAndCheckDiagnostics || !sourceFile.commentDirectives?.length) {
2318                return flatDiagnostics;
2319            }
2320
2321            const { diagnostics, directives } = getDiagnosticsWithPrecedingDirectives(sourceFile, sourceFile.commentDirectives, flatDiagnostics);
2322
2323            for (const errorExpectation of directives.getUnusedExpectations()) {
2324                diagnostics.push(createDiagnosticForRange(sourceFile, errorExpectation.range, Diagnostics.Unused_ts_expect_error_directive));
2325            }
2326
2327            return diagnostics;
2328        }
2329
2330        /**
2331         * Creates a map of comment directives along with the diagnostics immediately preceded by one of them.
2332         * Comments that match to any of those diagnostics are marked as used.
2333         */
2334        function getDiagnosticsWithPrecedingDirectives(sourceFile: SourceFile, commentDirectives: CommentDirective[], flatDiagnostics: Diagnostic[]) {
2335            // Diagnostics are only reported if there is no comment directive preceding them
2336            // This will modify the directives map by marking "used" ones with a corresponding diagnostic
2337            const directives = createCommentDirectivesMap(sourceFile, commentDirectives);
2338            const diagnostics = flatDiagnostics.filter(diagnostic => markPrecedingCommentDirectiveLine(diagnostic, directives) === -1);
2339
2340            return { diagnostics, directives };
2341        }
2342
2343        function getSuggestionDiagnostics(sourceFile: SourceFile, cancellationToken: CancellationToken): readonly DiagnosticWithLocation[] {
2344            return runWithCancellationToken(() => {
2345                return getTypeChecker().getSuggestionDiagnostics(sourceFile, cancellationToken);
2346            });
2347        }
2348
2349        /**
2350         * @returns The line index marked as preceding the diagnostic, or -1 if none was.
2351         */
2352        function markPrecedingCommentDirectiveLine(diagnostic: Diagnostic, directives: CommentDirectivesMap) {
2353            const { file, start } = diagnostic;
2354            if (!file) {
2355                return -1;
2356            }
2357
2358            // Start out with the line just before the text
2359            const lineStarts = getLineStarts(file);
2360            let line = computeLineAndCharacterOfPosition(lineStarts, start!).line - 1; // TODO: GH#18217
2361            while (line >= 0) {
2362                // As soon as that line is known to have a comment directive, use that
2363                if (directives.markUsed(line)) {
2364                    return line;
2365                }
2366
2367                // Stop searching if the line is not empty and not a comment
2368                const lineText = file.text.slice(lineStarts[line], lineStarts[line + 1]).trim();
2369                if (lineText !== "" && !/^(\s*)\/\/(.*)$/.test(lineText)) {
2370                    return -1;
2371                }
2372
2373                line--;
2374            }
2375
2376            return -1;
2377        }
2378
2379        function getJSSyntacticDiagnosticsForFile(sourceFile: SourceFile): DiagnosticWithLocation[] {
2380            return runWithCancellationToken(() => {
2381                const diagnostics: DiagnosticWithLocation[] = [];
2382                walk(sourceFile, sourceFile);
2383                forEachChildRecursively(sourceFile, walk, walkArray);
2384
2385                return diagnostics;
2386
2387                function walk(node: Node, parent: Node) {
2388                    // Return directly from the case if the given node doesnt want to visit each child
2389                    // Otherwise break to visit each child
2390
2391                    switch (parent.kind) {
2392                        case SyntaxKind.Parameter:
2393                        case SyntaxKind.PropertyDeclaration:
2394                        case SyntaxKind.MethodDeclaration:
2395                            if ((parent as ParameterDeclaration | PropertyDeclaration | MethodDeclaration).questionToken === node) {
2396                                diagnostics.push(createDiagnosticForNode(node, Diagnostics.The_0_modifier_can_only_be_used_in_TypeScript_files, "?"));
2397                                return "skip";
2398                            }
2399                        // falls through
2400                        case SyntaxKind.MethodSignature:
2401                        case SyntaxKind.Constructor:
2402                        case SyntaxKind.GetAccessor:
2403                        case SyntaxKind.SetAccessor:
2404                        case SyntaxKind.FunctionExpression:
2405                        case SyntaxKind.FunctionDeclaration:
2406                        case SyntaxKind.ArrowFunction:
2407                        case SyntaxKind.VariableDeclaration:
2408                            // type annotation
2409                            if ((parent as FunctionLikeDeclaration | VariableDeclaration | ParameterDeclaration | PropertyDeclaration).type === node) {
2410                                diagnostics.push(createDiagnosticForNode(node, Diagnostics.Type_annotations_can_only_be_used_in_TypeScript_files));
2411                                return "skip";
2412                            }
2413                    }
2414
2415                    switch (node.kind) {
2416                        case SyntaxKind.ImportClause:
2417                            if ((node as ImportClause).isTypeOnly) {
2418                                diagnostics.push(createDiagnosticForNode(parent, Diagnostics._0_declarations_can_only_be_used_in_TypeScript_files, "import type"));
2419                                return "skip";
2420                            }
2421                            break;
2422                        case SyntaxKind.ExportDeclaration:
2423                            if ((node as ExportDeclaration).isTypeOnly) {
2424                                diagnostics.push(createDiagnosticForNode(node, Diagnostics._0_declarations_can_only_be_used_in_TypeScript_files, "export type"));
2425                                return "skip";
2426                            }
2427                            break;
2428                        case SyntaxKind.ImportSpecifier:
2429                        case SyntaxKind.ExportSpecifier:
2430                            if ((node as ImportOrExportSpecifier).isTypeOnly) {
2431                                diagnostics.push(createDiagnosticForNode(node, Diagnostics._0_declarations_can_only_be_used_in_TypeScript_files, isImportSpecifier(node) ? "import...type" : "export...type"));
2432                                return "skip";
2433                            }
2434                            break;
2435                        case SyntaxKind.ImportEqualsDeclaration:
2436                            diagnostics.push(createDiagnosticForNode(node, Diagnostics.import_can_only_be_used_in_TypeScript_files));
2437                            return "skip";
2438                        case SyntaxKind.ExportAssignment:
2439                            if ((node as ExportAssignment).isExportEquals) {
2440                                diagnostics.push(createDiagnosticForNode(node, Diagnostics.export_can_only_be_used_in_TypeScript_files));
2441                                return "skip";
2442                            }
2443                            break;
2444                        case SyntaxKind.HeritageClause:
2445                            const heritageClause = node as HeritageClause;
2446                            if (heritageClause.token === SyntaxKind.ImplementsKeyword) {
2447                                diagnostics.push(createDiagnosticForNode(node, Diagnostics.implements_clauses_can_only_be_used_in_TypeScript_files));
2448                                return "skip";
2449                            }
2450                            break;
2451                        case SyntaxKind.InterfaceDeclaration:
2452                            const interfaceKeyword = tokenToString(SyntaxKind.InterfaceKeyword);
2453                            Debug.assertIsDefined(interfaceKeyword);
2454                            diagnostics.push(createDiagnosticForNode(node, Diagnostics._0_declarations_can_only_be_used_in_TypeScript_files, interfaceKeyword));
2455                            return "skip";
2456                        case SyntaxKind.ModuleDeclaration:
2457                            const moduleKeyword = node.flags & NodeFlags.Namespace ? tokenToString(SyntaxKind.NamespaceKeyword) : tokenToString(SyntaxKind.ModuleKeyword);
2458                            Debug.assertIsDefined(moduleKeyword);
2459                            diagnostics.push(createDiagnosticForNode(node, Diagnostics._0_declarations_can_only_be_used_in_TypeScript_files, moduleKeyword));
2460                            return "skip";
2461                        case SyntaxKind.TypeAliasDeclaration:
2462                            diagnostics.push(createDiagnosticForNode(node, Diagnostics.Type_aliases_can_only_be_used_in_TypeScript_files));
2463                            return "skip";
2464                        case SyntaxKind.EnumDeclaration:
2465                            const enumKeyword = Debug.checkDefined(tokenToString(SyntaxKind.EnumKeyword));
2466                            diagnostics.push(createDiagnosticForNode(node, Diagnostics._0_declarations_can_only_be_used_in_TypeScript_files, enumKeyword));
2467                            return "skip";
2468                        case SyntaxKind.NonNullExpression:
2469                            diagnostics.push(createDiagnosticForNode(node, Diagnostics.Non_null_assertions_can_only_be_used_in_TypeScript_files));
2470                            return "skip";
2471                        case SyntaxKind.AsExpression:
2472                            diagnostics.push(createDiagnosticForNode((node as AsExpression).type, Diagnostics.Type_assertion_expressions_can_only_be_used_in_TypeScript_files));
2473                            return "skip";
2474                        case SyntaxKind.SatisfiesExpression:
2475                            diagnostics.push(createDiagnosticForNode((node as SatisfiesExpression).type, Diagnostics.Type_satisfaction_expressions_can_only_be_used_in_TypeScript_files));
2476                            return "skip";
2477                        case SyntaxKind.TypeAssertionExpression:
2478                            Debug.fail(); // Won't parse these in a JS file anyway, as they are interpreted as JSX.
2479                    }
2480                }
2481
2482                function walkArray(nodes: NodeArray<Node>, parent: Node) {
2483                    if (canHaveModifiers(parent) && parent.modifiers === nodes && some(nodes, isDecorator) && !options.experimentalDecorators) {
2484                        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));
2485                    }
2486
2487                    switch (parent.kind) {
2488                        case SyntaxKind.ClassDeclaration:
2489                        case SyntaxKind.ClassExpression:
2490                        case SyntaxKind.StructDeclaration:
2491                        case SyntaxKind.MethodDeclaration:
2492                        case SyntaxKind.Constructor:
2493                        case SyntaxKind.GetAccessor:
2494                        case SyntaxKind.SetAccessor:
2495                        case SyntaxKind.FunctionExpression:
2496                        case SyntaxKind.FunctionDeclaration:
2497                        case SyntaxKind.ArrowFunction:
2498                            // Check type parameters
2499                            if (nodes === (parent as DeclarationWithTypeParameterChildren).typeParameters) {
2500                                diagnostics.push(createDiagnosticForNodeArray(nodes, Diagnostics.Type_parameter_declarations_can_only_be_used_in_TypeScript_files));
2501                                return "skip";
2502                            }
2503                        // falls through
2504
2505                        case SyntaxKind.VariableStatement:
2506                            // Check modifiers
2507                            if (nodes === (parent as VariableStatement).modifiers) {
2508                                checkModifiers((parent as VariableStatement).modifiers!, parent.kind === SyntaxKind.VariableStatement);
2509                                return "skip";
2510                            }
2511                            break;
2512                        case SyntaxKind.PropertyDeclaration:
2513                            // Check modifiers of property declaration
2514                            if (nodes === (parent as PropertyDeclaration).modifiers) {
2515                                for (const modifier of nodes as NodeArray<ModifierLike>) {
2516                                    if (isModifier(modifier)
2517                                        && modifier.kind !== SyntaxKind.StaticKeyword
2518                                        && modifier.kind !== SyntaxKind.AccessorKeyword) {
2519                                        diagnostics.push(createDiagnosticForNode(modifier, Diagnostics.The_0_modifier_can_only_be_used_in_TypeScript_files, tokenToString(modifier.kind)));
2520                                    }
2521                                }
2522                                return "skip";
2523                            }
2524                            break;
2525                        case SyntaxKind.Parameter:
2526                            // Check modifiers of parameter declaration
2527                            if (nodes === (parent as ParameterDeclaration).modifiers && some(nodes, isModifier)) {
2528                                diagnostics.push(createDiagnosticForNodeArray(nodes, Diagnostics.Parameter_modifiers_can_only_be_used_in_TypeScript_files));
2529                                return "skip";
2530                            }
2531                            break;
2532                        case SyntaxKind.CallExpression:
2533                        case SyntaxKind.NewExpression:
2534                        case SyntaxKind.ExpressionWithTypeArguments:
2535                        case SyntaxKind.JsxSelfClosingElement:
2536                        case SyntaxKind.JsxOpeningElement:
2537                        case SyntaxKind.TaggedTemplateExpression:
2538                            // Check type arguments
2539                            if (nodes === (parent as NodeWithTypeArguments).typeArguments) {
2540                                diagnostics.push(createDiagnosticForNodeArray(nodes, Diagnostics.Type_arguments_can_only_be_used_in_TypeScript_files));
2541                                return "skip";
2542                            }
2543                            break;
2544                    }
2545                }
2546
2547                function checkModifiers(modifiers: NodeArray<ModifierLike>, isConstValid: boolean) {
2548                    for (const modifier of modifiers) {
2549                        switch (modifier.kind) {
2550                            case SyntaxKind.ConstKeyword:
2551                                if (isConstValid) {
2552                                    continue;
2553                                }
2554                            // to report error,
2555                            // falls through
2556                            case SyntaxKind.PublicKeyword:
2557                            case SyntaxKind.PrivateKeyword:
2558                            case SyntaxKind.ProtectedKeyword:
2559                            case SyntaxKind.ReadonlyKeyword:
2560                            case SyntaxKind.DeclareKeyword:
2561                            case SyntaxKind.AbstractKeyword:
2562                            case SyntaxKind.OverrideKeyword:
2563                            case SyntaxKind.InKeyword:
2564                            case SyntaxKind.OutKeyword:
2565                                diagnostics.push(createDiagnosticForNode(modifier, Diagnostics.The_0_modifier_can_only_be_used_in_TypeScript_files, tokenToString(modifier.kind)));
2566                                break;
2567
2568                            // These are all legal modifiers.
2569                            case SyntaxKind.StaticKeyword:
2570                            case SyntaxKind.ExportKeyword:
2571                            case SyntaxKind.DefaultKeyword:
2572                            case SyntaxKind.AccessorKeyword:
2573                        }
2574                    }
2575                }
2576
2577                function createDiagnosticForNodeArray(nodes: NodeArray<Node>, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number): DiagnosticWithLocation {
2578                    const start = nodes.pos;
2579                    return createFileDiagnostic(sourceFile, start, nodes.end - start, message, arg0, arg1, arg2);
2580                }
2581
2582                // Since these are syntactic diagnostics, parent might not have been set
2583                // this means the sourceFile cannot be infered from the node
2584                function createDiagnosticForNode(node: Node, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number): DiagnosticWithLocation {
2585                    return createDiagnosticForNodeInSourceFile(sourceFile, node, message, arg0, arg1, arg2);
2586                }
2587            });
2588        }
2589
2590        function getDeclarationDiagnosticsWorker(sourceFile: SourceFile | undefined, cancellationToken: CancellationToken | undefined): readonly DiagnosticWithLocation[] {
2591            return getAndCacheDiagnostics(sourceFile, cancellationToken, cachedDeclarationDiagnosticsForFile, getDeclarationDiagnosticsForFileNoCache);
2592        }
2593
2594        function getDeclarationDiagnosticsForFileNoCache(sourceFile: SourceFile | undefined, cancellationToken: CancellationToken | undefined): readonly DiagnosticWithLocation[] {
2595            return runWithCancellationToken(() => {
2596                const resolver = getTypeChecker().getEmitResolver(sourceFile, cancellationToken);
2597                // Don't actually write any files since we're just getting diagnostics.
2598                return ts.getDeclarationDiagnostics(getEmitHost(noop), resolver, sourceFile) || emptyArray;
2599            });
2600        }
2601
2602        function getAndCacheDiagnostics<T extends SourceFile | undefined, U extends Diagnostic>(
2603            sourceFile: T,
2604            cancellationToken: CancellationToken | undefined,
2605            cache: DiagnosticCache<U>,
2606            getDiagnostics: (sourceFile: T, cancellationToken: CancellationToken | undefined, isForLinter?: boolean) => readonly U[],
2607            isForLinter?: boolean
2608        ): readonly U[] {
2609
2610            const cachedResult = sourceFile
2611                ? cache.perFile?.get(sourceFile.path)
2612                : cache.allDiagnostics;
2613
2614            if (cachedResult) {
2615                return cachedResult;
2616            }
2617
2618            let result;
2619            if (isForLinter !== undefined) {
2620                result = getDiagnostics(sourceFile, cancellationToken, isForLinter);
2621            } else {
2622                result = getDiagnostics(sourceFile, cancellationToken);
2623            }
2624
2625            if (sourceFile) {
2626                (cache.perFile || (cache.perFile = new Map())).set(sourceFile.path, result);
2627            }
2628            else {
2629                cache.allDiagnostics = result;
2630            }
2631            return result;
2632        }
2633
2634        function getDeclarationDiagnosticsForFile(sourceFile: SourceFile, cancellationToken: CancellationToken): readonly DiagnosticWithLocation[] {
2635            return sourceFile.isDeclarationFile ? [] : getDeclarationDiagnosticsWorker(sourceFile, cancellationToken);
2636        }
2637
2638        function getOptionsDiagnostics(): SortedReadonlyArray<Diagnostic> {
2639            return sortAndDeduplicateDiagnostics(concatenate(
2640                programDiagnostics.getGlobalDiagnostics(),
2641                getOptionsDiagnosticsOfConfigFile()
2642            ));
2643        }
2644
2645        function getOptionsDiagnosticsOfConfigFile() {
2646            if (!options.configFile) return emptyArray;
2647            let diagnostics = programDiagnostics.getDiagnostics(options.configFile.fileName);
2648            forEachResolvedProjectReference(resolvedRef => {
2649                diagnostics = concatenate(diagnostics, programDiagnostics.getDiagnostics(resolvedRef.sourceFile.fileName));
2650            });
2651            return diagnostics;
2652        }
2653
2654        function getGlobalDiagnostics(): SortedReadonlyArray<Diagnostic> {
2655            return rootNames.length ? sortAndDeduplicateDiagnostics(getTypeChecker().getGlobalDiagnostics().slice()) : emptyArray as any as SortedReadonlyArray<Diagnostic>;
2656        }
2657
2658        function getConfigFileParsingDiagnostics(): readonly Diagnostic[] {
2659            return configFileParsingDiagnostics || emptyArray;
2660        }
2661
2662        function processRootFile(fileName: string, isDefaultLib: boolean, ignoreNoDefaultLib: boolean, reason: FileIncludeReason) {
2663            processSourceFile(normalizePath(fileName), isDefaultLib, ignoreNoDefaultLib, /*packageId*/ undefined, reason);
2664        }
2665
2666        function fileReferenceIsEqualTo(a: FileReference, b: FileReference): boolean {
2667            return a.fileName === b.fileName;
2668        }
2669
2670        function moduleNameIsEqualTo(a: StringLiteralLike | Identifier, b: StringLiteralLike | Identifier): boolean {
2671            return a.kind === SyntaxKind.Identifier
2672                ? b.kind === SyntaxKind.Identifier && a.escapedText === b.escapedText
2673                : b.kind === SyntaxKind.StringLiteral && a.text === b.text;
2674        }
2675
2676        function createSyntheticImport(text: string, file: SourceFile) {
2677            const externalHelpersModuleReference = factory.createStringLiteral(text);
2678            const importDecl = factory.createImportDeclaration(/*modifiers*/ undefined, /*importClause*/ undefined, externalHelpersModuleReference, /*assertClause*/ undefined);
2679            addEmitFlags(importDecl, EmitFlags.NeverApplyImportHelper);
2680            setParent(externalHelpersModuleReference, importDecl);
2681            setParent(importDecl, file);
2682            // explicitly unset the synthesized flag on these declarations so the checker API will answer questions about them
2683            // (which is required to build the dependency graph for incremental emit)
2684            (externalHelpersModuleReference as Mutable<Node>).flags &= ~NodeFlags.Synthesized;
2685            (importDecl as Mutable<Node>).flags &= ~NodeFlags.Synthesized;
2686            return externalHelpersModuleReference;
2687        }
2688
2689        function collectExternalModuleReferences(file: SourceFile): void {
2690            if (file.imports) {
2691                return;
2692            }
2693
2694            const isJavaScriptFile = isSourceFileJS(file);
2695            const isExternalModuleFile = isExternalModule(file);
2696
2697            // file.imports may not be undefined if there exists dynamic import
2698            let imports: StringLiteralLike[] | undefined;
2699            let moduleAugmentations: (StringLiteral | Identifier)[] | undefined;
2700            let ambientModules: string[] | undefined;
2701
2702            // If we are importing helpers, we need to add a synthetic reference to resolve the
2703            // helpers library.
2704            if ((options.isolatedModules || isExternalModuleFile)
2705                && !file.isDeclarationFile) {
2706                if (options.importHelpers) {
2707                    // synthesize 'import "tslib"' declaration
2708                    imports = [createSyntheticImport(externalHelpersModuleNameText, file)];
2709                }
2710                const jsxImport = getJSXRuntimeImport(getJSXImplicitImportBase(options, file), options);
2711                if (jsxImport) {
2712                    // synthesize `import "base/jsx-runtime"` declaration
2713                    (imports ||= []).push(createSyntheticImport(jsxImport, file));
2714                }
2715            }
2716
2717            for (const node of file.statements) {
2718                collectModuleReferences(node, /*inAmbientModule*/ false);
2719            }
2720            if ((file.flags & NodeFlags.PossiblyContainsDynamicImport) || isJavaScriptFile) {
2721                collectDynamicImportOrRequireCalls(file);
2722            }
2723
2724            file.imports = imports || emptyArray;
2725            file.moduleAugmentations = moduleAugmentations || emptyArray;
2726            file.ambientModuleNames = ambientModules || emptyArray;
2727
2728            return;
2729
2730            function collectModuleReferences(node: Statement, inAmbientModule: boolean): void {
2731                if (isAnyImportOrReExport(node)) {
2732                    const moduleNameExpr = getExternalModuleName(node);
2733                    // TypeScript 1.0 spec (April 2014): 12.1.6
2734                    // An ExternalImportDeclaration in an AmbientExternalModuleDeclaration may reference other external modules
2735                    // only through top - level external module names. Relative external module names are not permitted.
2736                    if (moduleNameExpr && isStringLiteral(moduleNameExpr) && moduleNameExpr.text && (!inAmbientModule || !isExternalModuleNameRelative(moduleNameExpr.text))) {
2737                        setParentRecursive(node, /*incremental*/ false); // we need parent data on imports before the program is fully bound, so we ensure it's set here
2738                        imports = append(imports, moduleNameExpr);
2739                        if (!usesUriStyleNodeCoreModules && currentNodeModulesDepth === 0 && !file.isDeclarationFile) {
2740                            usesUriStyleNodeCoreModules = startsWith(moduleNameExpr.text, "node:");
2741                        }
2742                    }
2743                }
2744                else if (isModuleDeclaration(node)) {
2745                    if (isAmbientModule(node) && (inAmbientModule || hasSyntacticModifier(node, ModifierFlags.Ambient) || file.isDeclarationFile)) {
2746                        (node.name as Mutable<Node>).parent = node;
2747                        const nameText = getTextOfIdentifierOrLiteral(node.name);
2748                        // Ambient module declarations can be interpreted as augmentations for some existing external modules.
2749                        // This will happen in two cases:
2750                        // - if current file is external module then module augmentation is a ambient module declaration defined in the top level scope
2751                        // - if current file is not external module then module augmentation is an ambient module declaration with non-relative module name
2752                        //   immediately nested in top level ambient module declaration .
2753                        if (isExternalModuleFile || (inAmbientModule && !isExternalModuleNameRelative(nameText))) {
2754                            (moduleAugmentations || (moduleAugmentations = [])).push(node.name);
2755                        }
2756                        else if (!inAmbientModule) {
2757                            if (file.isDeclarationFile) {
2758                                // for global .d.ts files record name of ambient module
2759                                (ambientModules || (ambientModules = [])).push(nameText);
2760                            }
2761                            // An AmbientExternalModuleDeclaration declares an external module.
2762                            // This type of declaration is permitted only in the global module.
2763                            // The StringLiteral must specify a top - level external module name.
2764                            // Relative external module names are not permitted
2765
2766                            // NOTE: body of ambient module is always a module block, if it exists
2767                            const body = (node as ModuleDeclaration).body as ModuleBlock;
2768                            if (body) {
2769                                for (const statement of body.statements) {
2770                                    collectModuleReferences(statement, /*inAmbientModule*/ true);
2771                                }
2772                            }
2773                        }
2774                    }
2775                }
2776            }
2777
2778            function collectDynamicImportOrRequireCalls(file: SourceFile) {
2779                const r = /import|require/g;
2780                while (r.exec(file.text) !== null) { // eslint-disable-line no-null/no-null
2781                    const node = getNodeAtPosition(file, r.lastIndex);
2782                    if (isJavaScriptFile && isRequireCall(node, /*checkArgumentIsStringLiteralLike*/ true)) {
2783                        setParentRecursive(node, /*incremental*/ false); // we need parent data on imports before the program is fully bound, so we ensure it's set here
2784                        imports = append(imports, node.arguments[0]);
2785                    }
2786                    // 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.
2787                    else if (isImportCall(node) && node.arguments.length >= 1 && isStringLiteralLike(node.arguments[0])) {
2788                        setParentRecursive(node, /*incremental*/ false); // we need parent data on imports before the program is fully bound, so we ensure it's set here
2789                        imports = append(imports, node.arguments[0]);
2790                    }
2791                    else if (isLiteralImportTypeNode(node)) {
2792                        setParentRecursive(node, /*incremental*/ false); // we need parent data on imports before the program is fully bound, so we ensure it's set here
2793                        imports = append(imports, node.argument.literal);
2794                    }
2795                }
2796            }
2797
2798            /** Returns a token if position is in [start-of-leading-trivia, end), includes JSDoc only in JS files */
2799            function getNodeAtPosition(sourceFile: SourceFile, position: number): Node {
2800                let current: Node = sourceFile;
2801                const getContainingChild = (child: Node) => {
2802                    if (child.pos <= position && (position < child.end || (position === child.end && (child.kind === SyntaxKind.EndOfFileToken)))) {
2803                        return child;
2804                    }
2805                };
2806                while (true) {
2807                    const child = isJavaScriptFile && hasJSDocNodes(current) && forEach(current.jsDoc, getContainingChild) || forEachChild(current, getContainingChild);
2808                    if (!child) {
2809                        return current;
2810                    }
2811                    current = child;
2812                }
2813            }
2814        }
2815
2816        function getLibFileFromReference(ref: FileReference) {
2817            const libName = toFileNameLowerCase(ref.fileName);
2818            const libFileName = libMap.get(libName);
2819            if (libFileName) {
2820                return getSourceFile(pathForLibFile(libFileName));
2821            }
2822        }
2823
2824        /** This should have similar behavior to 'processSourceFile' without diagnostics or mutation. */
2825        function getSourceFileFromReference(referencingFile: SourceFile | UnparsedSource, ref: FileReference): SourceFile | undefined {
2826            return getSourceFileFromReferenceWorker(resolveTripleslashReference(ref.fileName, referencingFile.fileName), getSourceFile);
2827        }
2828
2829        function getSourceFileFromReferenceWorker(
2830            fileName: string,
2831            getSourceFile: (fileName: string) => SourceFile | undefined,
2832            fail?: (diagnostic: DiagnosticMessage, ...argument: string[]) => void,
2833            reason?: FileIncludeReason): SourceFile | undefined {
2834
2835            if (hasExtension(fileName)) {
2836                const canonicalFileName = host.getCanonicalFileName(fileName);
2837                if (!options.allowNonTsExtensions && !forEach(flatten(supportedExtensionsWithJsonIfResolveJsonModule), extension => fileExtensionIs(canonicalFileName, extension)) && !fileExtensionIs(canonicalFileName, Extension.Ets)) {
2838                    if (fail) {
2839                        if (hasJSFileExtension(canonicalFileName)) {
2840                            fail(Diagnostics.File_0_is_a_JavaScript_file_Did_you_mean_to_enable_the_allowJs_option, fileName);
2841                        }
2842                        else {
2843                            fail(Diagnostics.File_0_has_an_unsupported_extension_The_only_supported_extensions_are_1, fileName, "'" + flatten(supportedExtensions).join("', '") + "'");
2844                        }
2845                    }
2846                    return undefined;
2847                }
2848
2849                const sourceFile = getSourceFile(fileName);
2850                if (fail) {
2851                    if (!sourceFile) {
2852                        const redirect = getProjectReferenceRedirect(fileName);
2853                        if (redirect) {
2854                            fail(Diagnostics.Output_file_0_has_not_been_built_from_source_file_1, redirect, fileName);
2855                        }
2856                        else {
2857                            fail(Diagnostics.File_0_not_found, fileName);
2858                        }
2859                    }
2860                    else if (isReferencedFile(reason) && canonicalFileName === host.getCanonicalFileName(getSourceFileByPath(reason.file)!.fileName)) {
2861                        fail(Diagnostics.A_file_cannot_have_a_reference_to_itself);
2862                    }
2863                }
2864                return sourceFile;
2865            }
2866            else {
2867                const sourceFileNoExtension = options.allowNonTsExtensions && getSourceFile(fileName);
2868                if (sourceFileNoExtension) return sourceFileNoExtension;
2869
2870                if (fail && options.allowNonTsExtensions) {
2871                    fail(Diagnostics.File_0_not_found, fileName);
2872                    return undefined;
2873                }
2874
2875                // Only try adding extensions from the first supported group (which should be .ts/.tsx/.d.ts)
2876                const sourceFileWithAddedExtension = forEach(supportedExtensions[0], extension => getSourceFile(fileName + extension));
2877                if (fail && !sourceFileWithAddedExtension) fail(Diagnostics.Could_not_resolve_the_path_0_with_the_extensions_Colon_1, fileName, "'" + flatten(supportedExtensions).join("', '") + "'");
2878                return sourceFileWithAddedExtension;
2879            }
2880        }
2881
2882        /** This has side effects through `findSourceFile`. */
2883        function processSourceFile(fileName: string, isDefaultLib: boolean, ignoreNoDefaultLib: boolean, packageId: PackageId | undefined, reason: FileIncludeReason): void {
2884            getSourceFileFromReferenceWorker(
2885                fileName,
2886                fileName => findSourceFile(fileName, isDefaultLib, ignoreNoDefaultLib, reason, packageId), // TODO: GH#18217
2887                (diagnostic, ...args) => addFilePreprocessingFileExplainingDiagnostic(/*file*/ undefined, reason, diagnostic, args),
2888                reason
2889            );
2890        }
2891
2892        function processProjectReferenceFile(fileName: string, reason: ProjectReferenceFile) {
2893            return processSourceFile(fileName, /*isDefaultLib*/ false, /*ignoreNoDefaultLib*/ false, /*packageId*/ undefined, reason);
2894        }
2895
2896        function reportFileNamesDifferOnlyInCasingError(fileName: string, existingFile: SourceFile, reason: FileIncludeReason): void {
2897            const hasExistingReasonToReportErrorOn = !isReferencedFile(reason) && some(fileReasons.get(existingFile.path), isReferencedFile);
2898            if (hasExistingReasonToReportErrorOn) {
2899                addFilePreprocessingFileExplainingDiagnostic(existingFile, reason, Diagnostics.Already_included_file_name_0_differs_from_file_name_1_only_in_casing, [existingFile.fileName, fileName]);
2900            }
2901            else {
2902                addFilePreprocessingFileExplainingDiagnostic(existingFile, reason, Diagnostics.File_name_0_differs_from_already_included_file_name_1_only_in_casing, [fileName, existingFile.fileName]);
2903            }
2904        }
2905
2906        function createRedirectSourceFile(redirectTarget: SourceFile, unredirected: SourceFile, fileName: string, path: Path, resolvedPath: Path, originalFileName: string, sourceFileOptions: CreateSourceFileOptions): SourceFile {
2907            const redirect: SourceFile = Object.create(redirectTarget);
2908            redirect.fileName = fileName;
2909            redirect.path = path;
2910            redirect.resolvedPath = resolvedPath;
2911            redirect.originalFileName = originalFileName;
2912            redirect.redirectInfo = { redirectTarget, unredirected };
2913            redirect.packageJsonLocations = sourceFileOptions.packageJsonLocations?.length ? sourceFileOptions.packageJsonLocations : undefined;
2914            redirect.packageJsonScope = sourceFileOptions.packageJsonScope;
2915            sourceFilesFoundSearchingNodeModules.set(path, currentNodeModulesDepth > 0);
2916            Object.defineProperties(redirect, {
2917                id: {
2918                    get(this: SourceFile) { return this.redirectInfo!.redirectTarget.id; },
2919                    set(this: SourceFile, value: SourceFile["id"]) { this.redirectInfo!.redirectTarget.id = value; },
2920                },
2921                symbol: {
2922                    get(this: SourceFile) { return this.redirectInfo!.redirectTarget.symbol; },
2923                    set(this: SourceFile, value: SourceFile["symbol"]) { this.redirectInfo!.redirectTarget.symbol = value; },
2924                },
2925            });
2926            return redirect;
2927        }
2928
2929        // Get source file from normalized fileName
2930        function findSourceFile(fileName: string, isDefaultLib: boolean, ignoreNoDefaultLib: boolean, reason: FileIncludeReason, packageId: PackageId | undefined): SourceFile | undefined {
2931            tracing?.push(tracing.Phase.Program, "findSourceFile", {
2932                fileName,
2933                isDefaultLib: isDefaultLib || undefined,
2934                fileIncludeKind: (FileIncludeKind as any)[reason.kind],
2935            });
2936            const result = findSourceFileWorker(fileName, isDefaultLib, ignoreNoDefaultLib, reason, packageId);
2937            tracing?.pop();
2938            return result;
2939        }
2940
2941        function getCreateSourceFileOptions(fileName: string, moduleResolutionCache: ModuleResolutionCache | undefined, host: CompilerHost, options: CompilerOptions): CreateSourceFileOptions {
2942            // 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
2943            // 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
2944            // 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.
2945            const result = getImpliedNodeFormatForFileWorker(getNormalizedAbsolutePath(fileName, currentDirectory), moduleResolutionCache?.getPackageJsonInfoCache(), host, options);
2946            const languageVersion = getEmitScriptTarget(options);
2947            const setExternalModuleIndicator = getSetExternalModuleIndicator(options);
2948            return typeof result === "object" ?
2949                { ...result, languageVersion, setExternalModuleIndicator } :
2950                { languageVersion, impliedNodeFormat: result, setExternalModuleIndicator };
2951        }
2952
2953        function findSourceFileWorker(fileName: string, isDefaultLib: boolean, ignoreNoDefaultLib: boolean, reason: FileIncludeReason, packageId: PackageId | undefined): SourceFile | undefined {
2954            const path = toPath(fileName);
2955            if (useSourceOfProjectReferenceRedirect) {
2956                let source = getSourceOfProjectReferenceRedirect(path);
2957                // If preserveSymlinks is true, module resolution wont jump the symlink
2958                // but the resolved real path may be the .d.ts from project reference
2959                // Note:: Currently we try the real path only if the
2960                // file is from node_modules or oh_modules to avoid having to run real path on all file paths
2961                const modulesPathPart: string = getModulePathPartByPMType(options.packageManagerType);
2962                if (!source &&
2963                    host.realpath &&
2964                    options.preserveSymlinks &&
2965                    isDeclarationFileName(fileName) &&
2966                    stringContains(fileName, modulesPathPart)) {
2967                    const realPath = toPath(host.realpath(fileName));
2968                    if (realPath !== path) source = getSourceOfProjectReferenceRedirect(realPath);
2969                }
2970                if (source) {
2971                    const file = isString(source) ?
2972                        findSourceFile(source, isDefaultLib, ignoreNoDefaultLib, reason, packageId) :
2973                        undefined;
2974                    if (file) addFileToFilesByName(file, path, /*redirectedPath*/ undefined);
2975                    return file;
2976                }
2977            }
2978            const originalFileName = fileName;
2979            if (filesByName.has(path)) {
2980                const file = filesByName.get(path);
2981                addFileIncludeReason(file || undefined, reason);
2982                // try to check if we've already seen this file but with a different casing in path
2983                // NOTE: this only makes sense for case-insensitive file systems, and only on files which are not redirected
2984                if (file && options.forceConsistentCasingInFileNames) {
2985                    const checkedName = file.fileName;
2986                    const isRedirect = toPath(checkedName) !== toPath(fileName);
2987                    if (isRedirect) {
2988                        fileName = getProjectReferenceRedirect(fileName) || fileName;
2989                    }
2990                    // Check if it differs only in drive letters its ok to ignore that error:
2991                    const checkedAbsolutePath = getNormalizedAbsolutePathWithoutRoot(checkedName, currentDirectory);
2992                    const inputAbsolutePath = getNormalizedAbsolutePathWithoutRoot(fileName, currentDirectory);
2993                    if (checkedAbsolutePath !== inputAbsolutePath) {
2994                        reportFileNamesDifferOnlyInCasingError(fileName, file, reason);
2995                    }
2996                }
2997
2998                // If the file was previously found via a node_modules or oh_modules search, but is now being processed as a root file,
2999                // then everything it sucks in may also be marked incorrectly, and needs to be checked again.
3000                if (file && sourceFilesFoundSearchingNodeModules.get(file.path) && currentNodeModulesDepth === 0) {
3001                    sourceFilesFoundSearchingNodeModules.set(file.path, false);
3002                    if (!options.noResolve) {
3003                        processReferencedFiles(file, isDefaultLib);
3004                        processTypeReferenceDirectives(file);
3005                    }
3006                    if (!options.noLib) {
3007                        processLibReferenceDirectives(file);
3008                    }
3009
3010                    modulesWithElidedImports.set(file.path, false);
3011                    processImportedModules(file);
3012                }
3013                // See if we need to reprocess the imports due to prior skipped imports
3014                else if (file && modulesWithElidedImports.get(file.path)) {
3015                    if (currentNodeModulesDepth < maxNodeModuleJsDepth) {
3016                        modulesWithElidedImports.set(file.path, false);
3017                        processImportedModules(file);
3018                    }
3019                }
3020
3021                return file || undefined;
3022            }
3023
3024            let redirectedPath: Path | undefined;
3025            if (isReferencedFile(reason) && !useSourceOfProjectReferenceRedirect) {
3026                const redirectProject = getProjectReferenceRedirectProject(fileName);
3027                if (redirectProject) {
3028                    if (outFile(redirectProject.commandLine.options)) {
3029                        // Shouldnt create many to 1 mapping file in --out scenario
3030                        return undefined;
3031                    }
3032                    const redirect = getProjectReferenceOutputName(redirectProject, fileName);
3033                    fileName = redirect;
3034                    // Once we start redirecting to a file, we can potentially come back to it
3035                    // via a back-reference from another file in the .d.ts folder. If that happens we'll
3036                    // end up trying to add it to the program *again* because we were tracking it via its
3037                    // original (un-redirected) name. So we have to map both the original path and the redirected path
3038                    // to the source file we're about to find/create
3039                    redirectedPath = toPath(redirect);
3040                }
3041            }
3042
3043            // We haven't looked for this file, do so now and cache result
3044            const sourceFileOptions = getCreateSourceFileOptions(fileName, moduleResolutionCache, host, options);
3045            const file = host.getSourceFile(
3046                fileName,
3047                sourceFileOptions,
3048                hostErrorMessage => addFilePreprocessingFileExplainingDiagnostic(/*file*/ undefined, reason, Diagnostics.Cannot_read_file_0_Colon_1, [fileName, hostErrorMessage]),
3049                shouldCreateNewSourceFile || (oldProgram?.getSourceFileByPath(toPath(fileName))?.impliedNodeFormat !== sourceFileOptions.impliedNodeFormat),
3050                options
3051            );
3052
3053            if (packageId) {
3054                const packageIdKey = packageIdToString(packageId);
3055                const fileFromPackageId = packageIdToSourceFile.get(packageIdKey);
3056                if (fileFromPackageId) {
3057                    // Some other SourceFile already exists with this package name and version.
3058                    // Instead of creating a duplicate, just redirect to the existing one.
3059                    const dupFile = createRedirectSourceFile(fileFromPackageId, file!, fileName, path, toPath(fileName), originalFileName, sourceFileOptions);
3060                    redirectTargetsMap.add(fileFromPackageId.path, fileName);
3061                    addFileToFilesByName(dupFile, path, redirectedPath);
3062                    addFileIncludeReason(dupFile, reason);
3063                    sourceFileToPackageName.set(path, packageIdToPackageName(packageId));
3064                    processingOtherFiles!.push(dupFile);
3065                    return dupFile;
3066                }
3067                else if (file) {
3068                    // This is the first source file to have this packageId.
3069                    packageIdToSourceFile.set(packageIdKey, file);
3070                    sourceFileToPackageName.set(path, packageIdToPackageName(packageId));
3071                }
3072            }
3073            addFileToFilesByName(file, path, redirectedPath);
3074
3075            if (file) {
3076                sourceFilesFoundSearchingNodeModules.set(path, currentNodeModulesDepth > 0);
3077                file.fileName = fileName; // Ensure that source file has same name as what we were looking for
3078                file.path = path;
3079                file.resolvedPath = toPath(fileName);
3080                file.originalFileName = originalFileName;
3081                file.packageJsonLocations = sourceFileOptions.packageJsonLocations?.length ? sourceFileOptions.packageJsonLocations : undefined;
3082                file.packageJsonScope = sourceFileOptions.packageJsonScope;
3083                addFileIncludeReason(file, reason);
3084
3085                if (host.useCaseSensitiveFileNames()) {
3086                    const pathLowerCase = toFileNameLowerCase(path);
3087                    // for case-sensitive file systems check if we've already seen some file with similar filename ignoring case
3088                    const existingFile = filesByNameIgnoreCase!.get(pathLowerCase);
3089                    if (existingFile) {
3090                        reportFileNamesDifferOnlyInCasingError(fileName, existingFile, reason);
3091                    }
3092                    else {
3093                        filesByNameIgnoreCase!.set(pathLowerCase, file);
3094                    }
3095                }
3096
3097                skipDefaultLib = skipDefaultLib || (file.hasNoDefaultLib && !ignoreNoDefaultLib);
3098
3099                if (!options.noResolve) {
3100                    processReferencedFiles(file, isDefaultLib);
3101                    processTypeReferenceDirectives(file);
3102                }
3103                if (!options.noLib) {
3104                    processLibReferenceDirectives(file);
3105                }
3106
3107
3108                // always process imported modules to record module name resolutions
3109                processImportedModules(file);
3110
3111                if (isDefaultLib) {
3112                    processingDefaultLibFiles!.push(file);
3113                }
3114                else {
3115                    processingOtherFiles!.push(file);
3116                }
3117            }
3118            return file;
3119        }
3120
3121        function addFileIncludeReason(file: SourceFile | undefined, reason: FileIncludeReason) {
3122            if (file) fileReasons.add(file.path, reason);
3123        }
3124
3125        function addFileToFilesByName(file: SourceFile | undefined, path: Path, redirectedPath: Path | undefined) {
3126            if (redirectedPath) {
3127                filesByName.set(redirectedPath, file);
3128                filesByName.set(path, file || false);
3129            }
3130            else {
3131                filesByName.set(path, file);
3132            }
3133        }
3134
3135        function getProjectReferenceRedirect(fileName: string): string | undefined {
3136            const referencedProject = getProjectReferenceRedirectProject(fileName);
3137            return referencedProject && getProjectReferenceOutputName(referencedProject, fileName);
3138        }
3139
3140        function getProjectReferenceRedirectProject(fileName: string) {
3141            // Ignore dts or any json files
3142            if (!resolvedProjectReferences || !resolvedProjectReferences.length || isDeclarationFileName(fileName) || fileExtensionIs(fileName, Extension.Json)) {
3143                return undefined;
3144            }
3145
3146            // If this file is produced by a referenced project, we need to rewrite it to
3147            // look in the output folder of the referenced project rather than the input
3148            return getResolvedProjectReferenceToRedirect(fileName);
3149        }
3150
3151
3152        function getProjectReferenceOutputName(referencedProject: ResolvedProjectReference, fileName: string) {
3153            const out = outFile(referencedProject.commandLine.options);
3154            return out ?
3155                changeExtension(out, Extension.Dts) :
3156                getOutputDeclarationFileName(fileName, referencedProject.commandLine, !host.useCaseSensitiveFileNames());
3157        }
3158
3159        /**
3160         * Get the referenced project if the file is input file from that reference project
3161         */
3162        function getResolvedProjectReferenceToRedirect(fileName: string) {
3163            if (mapFromFileToProjectReferenceRedirects === undefined) {
3164                mapFromFileToProjectReferenceRedirects = new Map();
3165                forEachResolvedProjectReference(referencedProject => {
3166                    // not input file from the referenced project, ignore
3167                    if (toPath(options.configFilePath!) !== referencedProject.sourceFile.path) {
3168                        referencedProject.commandLine.fileNames.forEach(f =>
3169                            mapFromFileToProjectReferenceRedirects!.set(toPath(f), referencedProject.sourceFile.path));
3170                    }
3171                });
3172            }
3173
3174            const referencedProjectPath = mapFromFileToProjectReferenceRedirects.get(toPath(fileName));
3175            return referencedProjectPath && getResolvedProjectReferenceByPath(referencedProjectPath);
3176        }
3177
3178        function forEachResolvedProjectReference<T>(
3179            cb: (resolvedProjectReference: ResolvedProjectReference) => T | undefined
3180        ): T | undefined {
3181            return ts.forEachResolvedProjectReference(resolvedProjectReferences, cb);
3182        }
3183
3184        function getSourceOfProjectReferenceRedirect(path: Path) {
3185            if (!isDeclarationFileName(path)) return undefined;
3186            if (mapFromToProjectReferenceRedirectSource === undefined) {
3187                mapFromToProjectReferenceRedirectSource = new Map();
3188                forEachResolvedProjectReference(resolvedRef => {
3189                    const out = outFile(resolvedRef.commandLine.options);
3190                    if (out) {
3191                        // Dont know which source file it means so return true?
3192                        const outputDts = changeExtension(out, Extension.Dts);
3193                        mapFromToProjectReferenceRedirectSource!.set(toPath(outputDts), true);
3194                    }
3195                    else {
3196                        const getCommonSourceDirectory = memoize(() => getCommonSourceDirectoryOfConfig(resolvedRef.commandLine, !host.useCaseSensitiveFileNames()));
3197                        forEach(resolvedRef.commandLine.fileNames, fileName => {
3198                            if (!isDeclarationFileName(fileName) && !fileExtensionIs(fileName, Extension.Json)) {
3199                                const outputDts = getOutputDeclarationFileName(fileName, resolvedRef.commandLine, !host.useCaseSensitiveFileNames(), getCommonSourceDirectory);
3200                                mapFromToProjectReferenceRedirectSource!.set(toPath(outputDts), fileName);
3201                            }
3202                        });
3203                    }
3204                });
3205            }
3206            return mapFromToProjectReferenceRedirectSource.get(path);
3207        }
3208
3209        function isSourceOfProjectReferenceRedirect(fileName: string) {
3210            return useSourceOfProjectReferenceRedirect && !!getResolvedProjectReferenceToRedirect(fileName);
3211        }
3212
3213        function getResolvedProjectReferenceByPath(projectReferencePath: Path): ResolvedProjectReference | undefined {
3214            if (!projectReferenceRedirects) {
3215                return undefined;
3216            }
3217
3218            return projectReferenceRedirects.get(projectReferencePath) || undefined;
3219        }
3220
3221        function processReferencedFiles(file: SourceFile, isDefaultLib: boolean) {
3222            forEach(file.referencedFiles, (ref, index) => {
3223                processSourceFile(
3224                    resolveTripleslashReference(ref.fileName, file.fileName),
3225                    isDefaultLib,
3226                    /*ignoreNoDefaultLib*/ false,
3227                    /*packageId*/ undefined,
3228                    { kind: FileIncludeKind.ReferenceFile, file: file.path, index, }
3229                );
3230            });
3231        }
3232
3233        function processTypeReferenceDirectives(file: SourceFile) {
3234            const typeDirectives = file.typeReferenceDirectives;
3235            if (!typeDirectives) {
3236                return;
3237            }
3238
3239            const resolutions = resolveTypeReferenceDirectiveNamesWorker(typeDirectives, file);
3240            for (let index = 0; index < typeDirectives.length; index++) {
3241                const ref = file.typeReferenceDirectives[index];
3242                const resolvedTypeReferenceDirective = resolutions[index];
3243                // store resolved type directive on the file
3244                const fileName = toFileNameLowerCase(ref.fileName);
3245                setResolvedTypeReferenceDirective(file, fileName, resolvedTypeReferenceDirective);
3246                const mode = ref.resolutionMode || file.impliedNodeFormat;
3247                if (mode && getEmitModuleResolutionKind(options) !== ModuleResolutionKind.Node16 && getEmitModuleResolutionKind(options) !== ModuleResolutionKind.NodeNext) {
3248                    programDiagnostics.add(createDiagnosticForRange(file, ref, Diagnostics.resolution_mode_assertions_are_only_supported_when_moduleResolution_is_node16_or_nodenext));
3249                }
3250                processTypeReferenceDirective(fileName, mode, resolvedTypeReferenceDirective, { kind: FileIncludeKind.TypeReferenceDirective, file: file.path, index, });
3251            }
3252        }
3253
3254        function processTypeReferenceDirective(
3255            typeReferenceDirective: string,
3256            mode: SourceFile["impliedNodeFormat"] | undefined,
3257            resolvedTypeReferenceDirective: ResolvedTypeReferenceDirective | undefined,
3258            reason: FileIncludeReason
3259        ): void {
3260            tracing?.push(tracing.Phase.Program, "processTypeReferenceDirective", { directive: typeReferenceDirective, hasResolved: !!resolvedTypeReferenceDirective, refKind: reason.kind, refPath: isReferencedFile(reason) ? reason.file : undefined });
3261            processTypeReferenceDirectiveWorker(typeReferenceDirective, mode, resolvedTypeReferenceDirective, reason);
3262            tracing?.pop();
3263        }
3264
3265        function processTypeReferenceDirectiveWorker(
3266            typeReferenceDirective: string,
3267            mode: SourceFile["impliedNodeFormat"] | undefined,
3268            resolvedTypeReferenceDirective: ResolvedTypeReferenceDirective | undefined,
3269            reason: FileIncludeReason
3270        ): void {
3271
3272            // If we already found this library as a primary reference - nothing to do
3273            const previousResolution = resolvedTypeReferenceDirectives.get(typeReferenceDirective, mode);
3274            if (previousResolution && previousResolution.primary) {
3275                return;
3276            }
3277            let saveResolution = true;
3278            if (resolvedTypeReferenceDirective) {
3279                if (resolvedTypeReferenceDirective.isExternalLibraryImport) currentNodeModulesDepth++;
3280
3281                if (resolvedTypeReferenceDirective.primary) {
3282                    // resolved from the primary path
3283                    processSourceFile(resolvedTypeReferenceDirective.resolvedFileName!, /*isDefaultLib*/ false, /*ignoreNoDefaultLib*/ false, resolvedTypeReferenceDirective.packageId, reason); // TODO: GH#18217
3284                }
3285                else {
3286                    // If we already resolved to this file, it must have been a secondary reference. Check file contents
3287                    // for sameness and possibly issue an error
3288                    if (previousResolution) {
3289                        // Don't bother reading the file again if it's the same file.
3290                        if (resolvedTypeReferenceDirective.resolvedFileName !== previousResolution.resolvedFileName) {
3291                            const otherFileText = host.readFile(resolvedTypeReferenceDirective.resolvedFileName!);
3292                            const existingFile = getSourceFile(previousResolution.resolvedFileName!)!;
3293                            if (otherFileText !== existingFile.text) {
3294                                addFilePreprocessingFileExplainingDiagnostic(
3295                                    existingFile,
3296                                    reason,
3297                                    Diagnostics.Conflicting_definitions_for_0_found_at_1_and_2_Consider_installing_a_specific_version_of_this_library_to_resolve_the_conflict,
3298                                    [typeReferenceDirective, resolvedTypeReferenceDirective.resolvedFileName, previousResolution.resolvedFileName]
3299                                );
3300                            }
3301                        }
3302                        // don't overwrite previous resolution result
3303                        saveResolution = false;
3304                    }
3305                    else {
3306                        // First resolution of this library
3307                        processSourceFile(resolvedTypeReferenceDirective.resolvedFileName!, /*isDefaultLib*/ false, /*ignoreNoDefaultLib*/ false, resolvedTypeReferenceDirective.packageId, reason);
3308                    }
3309                }
3310
3311                if (resolvedTypeReferenceDirective.isExternalLibraryImport) currentNodeModulesDepth--;
3312            }
3313            else {
3314                addFilePreprocessingFileExplainingDiagnostic(/*file*/ undefined, reason, Diagnostics.Cannot_find_type_definition_file_for_0, [typeReferenceDirective]);
3315            }
3316
3317            if (saveResolution) {
3318                resolvedTypeReferenceDirectives.set(typeReferenceDirective, mode, resolvedTypeReferenceDirective);
3319            }
3320        }
3321
3322        function pathForLibFile(libFileName: string): string {
3323            // Support resolving to lib.dom.d.ts -> @typescript/lib-dom, and
3324            //                      lib.dom.iterable.d.ts -> @typescript/lib-dom/iterable
3325            //                      lib.es2015.symbol.wellknown.d.ts -> @typescript/lib-es2015/symbol-wellknown
3326            const components = libFileName.split(".");
3327            let path = components[1];
3328            let i = 2;
3329            while (components[i] && components[i] !== "d") {
3330                path += (i === 2 ? "/" : "-") + components[i];
3331                i++;
3332            }
3333            const modulePathType = getModuleByPMType(options.packageManagerType);
3334            const resolveFrom = combinePaths(currentDirectory, `__lib_${modulePathType}_lookup_${libFileName}__.ts`);
3335            const localOverrideModuleResult = resolveModuleName("@typescript/lib-" + path, resolveFrom, { moduleResolution: ModuleResolutionKind.NodeJs }, host, moduleResolutionCache);
3336            if (localOverrideModuleResult?.resolvedModule) {
3337                return localOverrideModuleResult.resolvedModule.resolvedFileName;
3338            }
3339            return combinePaths(defaultLibraryPath, libFileName);
3340        }
3341
3342        function processLibReferenceDirectives(file: SourceFile) {
3343            forEach(file.libReferenceDirectives, (libReference, index) => {
3344                const libName = toFileNameLowerCase(libReference.fileName);
3345                const libFileName = libMap.get(libName);
3346                if (libFileName) {
3347                    // we ignore any 'no-default-lib' reference set on this file.
3348                    processRootFile(pathForLibFile(libFileName), /*isDefaultLib*/ true, /*ignoreNoDefaultLib*/ true, { kind: FileIncludeKind.LibReferenceDirective, file: file.path, index, });
3349                }
3350                else {
3351                    const unqualifiedLibName = removeSuffix(removePrefix(libName, "lib."), ".d.ts");
3352                    const suggestion = getSpellingSuggestion(unqualifiedLibName, libs, identity);
3353                    const diagnostic = suggestion ? Diagnostics.Cannot_find_lib_definition_for_0_Did_you_mean_1 : Diagnostics.Cannot_find_lib_definition_for_0;
3354                    (fileProcessingDiagnostics ||= []).push({
3355                        kind: FilePreprocessingDiagnosticsKind.FilePreprocessingReferencedDiagnostic,
3356                        reason: { kind: FileIncludeKind.LibReferenceDirective, file: file.path, index, },
3357                        diagnostic,
3358                        args: [libName, suggestion]
3359                    });
3360                }
3361            });
3362        }
3363
3364        function getCanonicalFileName(fileName: string): string {
3365            return host.getCanonicalFileName(fileName);
3366        }
3367
3368        function processImportedModules(file: SourceFile) {
3369            collectExternalModuleReferences(file);
3370            if (file.imports.length || file.moduleAugmentations.length) {
3371                // Because global augmentation doesn't have string literal name, we can check for global augmentation as such.
3372                const moduleNames = getModuleNames(file);
3373                const resolutions = resolveModuleNamesReusingOldState(moduleNames, file);
3374                Debug.assert(resolutions.length === moduleNames.length);
3375                const optionsForFile = (useSourceOfProjectReferenceRedirect ? getRedirectReferenceForResolution(file)?.commandLine.options : undefined) || options;
3376                for (let index = 0; index < moduleNames.length; index++) {
3377                    const resolution = resolutions[index];
3378                    setResolvedModule(file, moduleNames[index], resolution, getModeForResolutionAtIndex(file, index));
3379
3380                    if (!resolution) {
3381                        continue;
3382                    }
3383
3384                    const isFromNodeModulesSearch = resolution.isExternalLibraryImport;
3385                    const isJsFile = !resolutionExtensionIsTSOrJson(resolution.extension);
3386                    const isJsFileFromNodeModules = isFromNodeModulesSearch && isJsFile;
3387                    const resolvedFileName = resolution.resolvedFileName;
3388
3389                    if (isFromNodeModulesSearch) {
3390                        currentNodeModulesDepth++;
3391                    }
3392
3393                    // add file to program only if:
3394                    // - resolution was successful
3395                    // - noResolve is falsy
3396                    // - module name comes from the list of imports
3397                    // - it's not a top level JavaScript module that exceeded the search max
3398                    const elideImport = isJsFileFromNodeModules && currentNodeModulesDepth > maxNodeModuleJsDepth;
3399                    // Don't add the file if it has a bad extension (e.g. 'tsx' if we don't have '--allowJs')
3400                    // This may still end up being an untyped module -- the file won't be included but imports will be allowed.
3401                    const shouldAddFile = resolvedFileName
3402                        && !getResolutionDiagnostic(optionsForFile, resolution)
3403                        && !optionsForFile.noResolve
3404                        && index < file.imports.length
3405                        && !elideImport
3406                        && !(isJsFile && !getAllowJSCompilerOption(optionsForFile))
3407                        && (isInJSFile(file.imports[index]) || !(file.imports[index].flags & NodeFlags.JSDoc));
3408
3409                    if (elideImport) {
3410                        modulesWithElidedImports.set(file.path, true);
3411                    }
3412                    else if (shouldAddFile) {
3413                        findSourceFile(
3414                            resolvedFileName,
3415                            /*isDefaultLib*/ false,
3416                            /*ignoreNoDefaultLib*/ false,
3417                            { kind: FileIncludeKind.Import, file: file.path, index, },
3418                            resolution.packageId,
3419                        );
3420                    }
3421
3422                    if (isFromNodeModulesSearch) {
3423                        currentNodeModulesDepth--;
3424                    }
3425                }
3426            }
3427            else {
3428                // no imports - drop cached module resolutions
3429                file.resolvedModules = undefined;
3430            }
3431        }
3432
3433        function checkSourceFilesBelongToPath(sourceFiles: readonly SourceFile[], rootDirectory: string): boolean {
3434            let allFilesBelongToPath = true;
3435            const absoluteRootDirectoryPath = host.getCanonicalFileName(getNormalizedAbsolutePath(rootDirectory, currentDirectory));
3436            for (const sourceFile of sourceFiles) {
3437                if (!sourceFile.isDeclarationFile) {
3438                    const absoluteSourceFilePath = host.getCanonicalFileName(getNormalizedAbsolutePath(sourceFile.fileName, currentDirectory));
3439                    if (absoluteSourceFilePath.indexOf(absoluteRootDirectoryPath) !== 0) {
3440                        addProgramDiagnosticExplainingFile(
3441                            sourceFile,
3442                            Diagnostics.File_0_is_not_under_rootDir_1_rootDir_is_expected_to_contain_all_source_files,
3443                            [sourceFile.fileName, rootDirectory]
3444                        );
3445                        allFilesBelongToPath = false;
3446                    }
3447                }
3448            }
3449
3450            return allFilesBelongToPath;
3451        }
3452
3453        function parseProjectReferenceConfigFile(ref: ProjectReference): ResolvedProjectReference | undefined {
3454            if (!projectReferenceRedirects) {
3455                projectReferenceRedirects = new Map();
3456            }
3457
3458            // The actual filename (i.e. add "/tsconfig.json" if necessary)
3459            const refPath = resolveProjectReferencePath(ref);
3460            const sourceFilePath = toPath(refPath);
3461            const fromCache = projectReferenceRedirects.get(sourceFilePath);
3462            if (fromCache !== undefined) {
3463                return fromCache || undefined;
3464            }
3465
3466            let commandLine: ParsedCommandLine | undefined;
3467            let sourceFile: JsonSourceFile | undefined;
3468            if (host.getParsedCommandLine) {
3469                commandLine = host.getParsedCommandLine(refPath);
3470                if (!commandLine) {
3471                    addFileToFilesByName(/*sourceFile*/ undefined, sourceFilePath, /*redirectedPath*/ undefined);
3472                    projectReferenceRedirects.set(sourceFilePath, false);
3473                    return undefined;
3474                }
3475                sourceFile = Debug.checkDefined(commandLine.options.configFile);
3476                Debug.assert(!sourceFile.path || sourceFile.path === sourceFilePath);
3477                addFileToFilesByName(sourceFile, sourceFilePath, /*redirectedPath*/ undefined);
3478            }
3479            else {
3480                // An absolute path pointing to the containing directory of the config file
3481                const basePath = getNormalizedAbsolutePath(getDirectoryPath(refPath), host.getCurrentDirectory());
3482                sourceFile = host.getSourceFile(refPath, ScriptTarget.JSON) as JsonSourceFile | undefined;
3483                addFileToFilesByName(sourceFile, sourceFilePath, /*redirectedPath*/ undefined);
3484                if (sourceFile === undefined) {
3485                    projectReferenceRedirects.set(sourceFilePath, false);
3486                    return undefined;
3487                }
3488                commandLine = parseJsonSourceFileConfigFileContent(sourceFile, configParsingHost, basePath, /*existingOptions*/ undefined, refPath);
3489            }
3490            sourceFile.fileName = refPath;
3491            sourceFile.path = sourceFilePath;
3492            sourceFile.resolvedPath = sourceFilePath;
3493            sourceFile.originalFileName = refPath;
3494
3495            const resolvedRef: ResolvedProjectReference = { commandLine, sourceFile };
3496            projectReferenceRedirects.set(sourceFilePath, resolvedRef);
3497            if (commandLine.projectReferences) {
3498                resolvedRef.references = commandLine.projectReferences.map(parseProjectReferenceConfigFile);
3499            }
3500            return resolvedRef;
3501        }
3502
3503        function verifyCompilerOptions() {
3504            if (options.strictPropertyInitialization && !getStrictOptionValue(options, "strictNullChecks")) {
3505                createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1, "strictPropertyInitialization", "strictNullChecks");
3506            }
3507            if (options.exactOptionalPropertyTypes && !getStrictOptionValue(options, "strictNullChecks")) {
3508                createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1, "exactOptionalPropertyTypes", "strictNullChecks");
3509            }
3510
3511            if (options.isolatedModules) {
3512                if (options.out) {
3513                    createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_with_option_1, "out", "isolatedModules");
3514                }
3515
3516                if (options.outFile) {
3517                    createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_with_option_1, "outFile", "isolatedModules");
3518                }
3519            }
3520
3521            if (options.inlineSourceMap) {
3522                if (options.sourceMap) {
3523                    createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_with_option_1, "sourceMap", "inlineSourceMap");
3524                }
3525                if (options.mapRoot) {
3526                    createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_with_option_1, "mapRoot", "inlineSourceMap");
3527                }
3528            }
3529
3530            if (options.composite) {
3531                if (options.declaration === false) {
3532                    createDiagnosticForOptionName(Diagnostics.Composite_projects_may_not_disable_declaration_emit, "declaration");
3533                }
3534                if (options.incremental === false) {
3535                    createDiagnosticForOptionName(Diagnostics.Composite_projects_may_not_disable_incremental_compilation, "declaration");
3536                }
3537            }
3538
3539            const outputFile = outFile(options);
3540            if (options.tsBuildInfoFile) {
3541                if (!isIncrementalCompilation(options)) {
3542                    createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1_or_option_2, "tsBuildInfoFile", "incremental", "composite");
3543                }
3544            }
3545            else if (options.incremental && !outputFile && !options.configFilePath) {
3546                programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Option_incremental_can_only_be_specified_using_tsconfig_emitting_to_single_file_or_when_option_tsBuildInfoFile_is_specified));
3547            }
3548
3549            verifyProjectReferences();
3550
3551            // List of collected files is complete; validate exhautiveness if this is a project with a file list
3552            if (options.composite) {
3553                const rootPaths = new Set(rootNames.map(toPath));
3554                for (const file of files) {
3555                    // Ignore file that is not emitted
3556                    if (sourceFileMayBeEmitted(file, program) && !rootPaths.has(file.path)) {
3557                        addProgramDiagnosticExplainingFile(
3558                            file,
3559                            Diagnostics.File_0_is_not_listed_within_the_file_list_of_project_1_Projects_must_list_all_files_or_use_an_include_pattern,
3560                            [file.fileName, options.configFilePath || ""]
3561                        );
3562                    }
3563                }
3564            }
3565
3566            if (options.paths) {
3567                for (const key in options.paths) {
3568                    if (!hasProperty(options.paths, key)) {
3569                        continue;
3570                    }
3571                    if (!hasZeroOrOneAsteriskCharacter(key)) {
3572                        createDiagnosticForOptionPaths(/*onKey*/ true, key, Diagnostics.Pattern_0_can_have_at_most_one_Asterisk_character, key);
3573                    }
3574                    if (isArray(options.paths[key])) {
3575                        const len = options.paths[key].length;
3576                        if (len === 0) {
3577                            createDiagnosticForOptionPaths(/*onKey*/ false, key, Diagnostics.Substitutions_for_pattern_0_shouldn_t_be_an_empty_array, key);
3578                        }
3579                        for (let i = 0; i < len; i++) {
3580                            const subst = options.paths[key][i];
3581                            const typeOfSubst = typeof subst;
3582                            if (typeOfSubst === "string") {
3583                                if (!hasZeroOrOneAsteriskCharacter(subst)) {
3584                                    createDiagnosticForOptionPathKeyValue(key, i, Diagnostics.Substitution_0_in_pattern_1_can_have_at_most_one_Asterisk_character, subst, key);
3585                                }
3586                                if (!options.baseUrl && !pathIsRelative(subst) && !pathIsAbsolute(subst)) {
3587                                    createDiagnosticForOptionPathKeyValue(key, i, Diagnostics.Non_relative_paths_are_not_allowed_when_baseUrl_is_not_set_Did_you_forget_a_leading_Slash);
3588                                }
3589                            }
3590                            else {
3591                                createDiagnosticForOptionPathKeyValue(key, i, Diagnostics.Substitution_0_for_pattern_1_has_incorrect_type_expected_string_got_2, subst, key, typeOfSubst);
3592                            }
3593                        }
3594                    }
3595                    else {
3596                        createDiagnosticForOptionPaths(/*onKey*/ false, key, Diagnostics.Substitutions_for_pattern_0_should_be_an_array, key);
3597                    }
3598                }
3599            }
3600
3601            if (!options.sourceMap && !options.inlineSourceMap) {
3602                if (options.inlineSources) {
3603                    createDiagnosticForOptionName(Diagnostics.Option_0_can_only_be_used_when_either_option_inlineSourceMap_or_option_sourceMap_is_provided, "inlineSources");
3604                }
3605                if (options.sourceRoot) {
3606                    createDiagnosticForOptionName(Diagnostics.Option_0_can_only_be_used_when_either_option_inlineSourceMap_or_option_sourceMap_is_provided, "sourceRoot");
3607                }
3608            }
3609
3610            if (options.out && options.outFile) {
3611                createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_with_option_1, "out", "outFile");
3612            }
3613
3614            if (options.mapRoot && !(options.sourceMap || options.declarationMap)) {
3615                // Error to specify --mapRoot without --sourcemap
3616                createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1_or_option_2, "mapRoot", "sourceMap", "declarationMap");
3617            }
3618
3619            if (options.declarationDir) {
3620                if (!getEmitDeclarations(options)) {
3621                    createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1_or_option_2, "declarationDir", "declaration", "composite");
3622                }
3623                if (outputFile) {
3624                    createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_with_option_1, "declarationDir", options.out ? "out" : "outFile");
3625                }
3626            }
3627
3628            if (options.declarationMap && !getEmitDeclarations(options)) {
3629                createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1_or_option_2, "declarationMap", "declaration", "composite");
3630            }
3631
3632            if (options.lib && options.noLib) {
3633                createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_with_option_1, "lib", "noLib");
3634            }
3635
3636            if (options.noImplicitUseStrict && getStrictOptionValue(options, "alwaysStrict")) {
3637                createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_with_option_1, "noImplicitUseStrict", "alwaysStrict");
3638            }
3639
3640            const languageVersion = getEmitScriptTarget(options);
3641
3642            const firstNonAmbientExternalModuleSourceFile = find(files, f => isExternalModule(f) && !f.isDeclarationFile);
3643            if (options.isolatedModules) {
3644                if (options.module === ModuleKind.None && languageVersion < ScriptTarget.ES2015) {
3645                    createDiagnosticForOptionName(Diagnostics.Option_isolatedModules_can_only_be_used_when_either_option_module_is_provided_or_option_target_is_ES2015_or_higher, "isolatedModules", "target");
3646                }
3647
3648                if (options.preserveConstEnums === false) {
3649                    createDiagnosticForOptionName(Diagnostics.Option_preserveConstEnums_cannot_be_disabled_when_isolatedModules_is_enabled, "preserveConstEnums", "isolatedModules");
3650                }
3651
3652                for (const file of files) {
3653                    if (!isExternalModule(file) && !isSourceFileJS(file) && !file.isDeclarationFile && file.scriptKind !== ScriptKind.JSON) {
3654                        const span = getErrorSpanForNode(file, file);
3655                        programDiagnostics.add(createFileDiagnostic(file, span.start, span.length,
3656                            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)));
3657                    }
3658                }
3659            }
3660            else if (firstNonAmbientExternalModuleSourceFile && languageVersion < ScriptTarget.ES2015 && options.module === ModuleKind.None) {
3661                // We cannot use createDiagnosticFromNode because nodes do not have parents yet
3662                const span = getErrorSpanForNode(firstNonAmbientExternalModuleSourceFile, typeof firstNonAmbientExternalModuleSourceFile.externalModuleIndicator === "boolean" ? firstNonAmbientExternalModuleSourceFile : firstNonAmbientExternalModuleSourceFile.externalModuleIndicator!);
3663                programDiagnostics.add(createFileDiagnostic(firstNonAmbientExternalModuleSourceFile, span.start, span.length, Diagnostics.Cannot_use_imports_exports_or_module_augmentations_when_module_is_none));
3664            }
3665
3666            // Cannot specify module gen that isn't amd or system with --out
3667            if (outputFile && !options.emitDeclarationOnly) {
3668                if (options.module && !(options.module === ModuleKind.AMD || options.module === ModuleKind.System)) {
3669                    createDiagnosticForOptionName(Diagnostics.Only_amd_and_system_modules_are_supported_alongside_0, options.out ? "out" : "outFile", "module");
3670                }
3671                else if (options.module === undefined && firstNonAmbientExternalModuleSourceFile) {
3672                    const span = getErrorSpanForNode(firstNonAmbientExternalModuleSourceFile, typeof firstNonAmbientExternalModuleSourceFile.externalModuleIndicator === "boolean" ? firstNonAmbientExternalModuleSourceFile : firstNonAmbientExternalModuleSourceFile.externalModuleIndicator!);
3673                    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"));
3674                }
3675            }
3676
3677            if (options.resolveJsonModule) {
3678                if (getEmitModuleResolutionKind(options) !== ModuleResolutionKind.NodeJs &&
3679                    getEmitModuleResolutionKind(options) !== ModuleResolutionKind.Node16 &&
3680                    getEmitModuleResolutionKind(options) !== ModuleResolutionKind.NodeNext) {
3681                    createDiagnosticForOptionName(Diagnostics.Option_resolveJsonModule_cannot_be_specified_without_node_module_resolution_strategy, "resolveJsonModule");
3682                }
3683                // Any emit other than common js, amd, es2015 or esnext is error
3684                else if (!hasJsonModuleEmitEnabled(options)) {
3685                    createDiagnosticForOptionName(Diagnostics.Option_resolveJsonModule_can_only_be_specified_when_module_code_generation_is_commonjs_amd_es2015_or_esNext, "resolveJsonModule", "module");
3686                }
3687            }
3688
3689            // there has to be common source directory if user specified --outdir || --rootDir || --sourceRoot
3690            // if user specified --mapRoot, there needs to be common source directory if there would be multiple files being emitted
3691            if (options.outDir || // there is --outDir specified
3692                options.rootDir || // there is --rootDir specified
3693                options.sourceRoot || // there is --sourceRoot specified
3694                options.mapRoot) { // there is --mapRoot specified
3695
3696                // Precalculate and cache the common source directory
3697                const dir = getCommonSourceDirectory();
3698
3699                // 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
3700                if (options.outDir && dir === "" && files.some(file => getRootLength(file.fileName) > 1)) {
3701                    createDiagnosticForOptionName(Diagnostics.Cannot_find_the_common_subdirectory_path_for_the_input_files, "outDir");
3702                }
3703            }
3704
3705            if (options.useDefineForClassFields && languageVersion === ScriptTarget.ES3) {
3706                createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_when_option_target_is_ES3, "useDefineForClassFields");
3707            }
3708
3709            if (options.checkJs && !getAllowJSCompilerOption(options)) {
3710                programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1, "checkJs", "allowJs"));
3711            }
3712
3713            if (options.emitDeclarationOnly) {
3714                if (!getEmitDeclarations(options)) {
3715                    createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1_or_option_2, "emitDeclarationOnly", "declaration", "composite");
3716                }
3717
3718                if (options.noEmit) {
3719                    createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_with_option_1, "emitDeclarationOnly", "noEmit");
3720                }
3721            }
3722
3723            if (options.emitDecoratorMetadata &&
3724                !options.experimentalDecorators) {
3725                createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1, "emitDecoratorMetadata", "experimentalDecorators");
3726            }
3727
3728            if (options.jsxFactory) {
3729                if (options.reactNamespace) {
3730                    createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_with_option_1, "reactNamespace", "jsxFactory");
3731                }
3732                if (options.jsx === JsxEmit.ReactJSX || options.jsx === JsxEmit.ReactJSXDev) {
3733                    createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_when_option_jsx_is_1, "jsxFactory", inverseJsxOptionMap.get("" + options.jsx));
3734                }
3735                if (!parseIsolatedEntityName(options.jsxFactory, languageVersion)) {
3736                    createOptionValueDiagnostic("jsxFactory", Diagnostics.Invalid_value_for_jsxFactory_0_is_not_a_valid_identifier_or_qualified_name, options.jsxFactory);
3737                }
3738            }
3739            else if (options.reactNamespace && !isIdentifierText(options.reactNamespace, languageVersion)) {
3740                createOptionValueDiagnostic("reactNamespace", Diagnostics.Invalid_value_for_reactNamespace_0_is_not_a_valid_identifier, options.reactNamespace);
3741            }
3742
3743            if (options.jsxFragmentFactory) {
3744                if (!options.jsxFactory) {
3745                    createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1, "jsxFragmentFactory", "jsxFactory");
3746                }
3747                if (options.jsx === JsxEmit.ReactJSX || options.jsx === JsxEmit.ReactJSXDev) {
3748                    createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_when_option_jsx_is_1, "jsxFragmentFactory", inverseJsxOptionMap.get("" + options.jsx));
3749                }
3750                if (!parseIsolatedEntityName(options.jsxFragmentFactory, languageVersion)) {
3751                    createOptionValueDiagnostic("jsxFragmentFactory", Diagnostics.Invalid_value_for_jsxFragmentFactory_0_is_not_a_valid_identifier_or_qualified_name, options.jsxFragmentFactory);
3752                }
3753            }
3754
3755            if (options.reactNamespace) {
3756                if (options.jsx === JsxEmit.ReactJSX || options.jsx === JsxEmit.ReactJSXDev) {
3757                    createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_when_option_jsx_is_1, "reactNamespace", inverseJsxOptionMap.get("" + options.jsx));
3758                }
3759            }
3760
3761            if (options.jsxImportSource) {
3762                if (options.jsx === JsxEmit.React) {
3763                    createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_when_option_jsx_is_1, "jsxImportSource", inverseJsxOptionMap.get("" + options.jsx));
3764                }
3765            }
3766
3767            if (options.preserveValueImports && getEmitModuleKind(options) < ModuleKind.ES2015) {
3768                createOptionValueDiagnostic("importsNotUsedAsValues", Diagnostics.Option_preserveValueImports_can_only_be_used_when_module_is_set_to_es2015_or_later);
3769            }
3770
3771            // If the emit is enabled make sure that every output file is unique and not overwriting any of the input files
3772            if (!options.noEmit && !options.suppressOutputPathCheck) {
3773                const emitHost = getEmitHost();
3774                const emitFilesSeen = new Set<string>();
3775                forEachEmittedFile(emitHost, (emitFileNames) => {
3776                    if (!options.emitDeclarationOnly) {
3777                        verifyEmitFilePath(emitFileNames.jsFilePath, emitFilesSeen);
3778                    }
3779                    verifyEmitFilePath(emitFileNames.declarationFilePath, emitFilesSeen);
3780                });
3781            }
3782
3783            // Verify that all the emit files are unique and don't overwrite input files
3784            function verifyEmitFilePath(emitFileName: string | undefined, emitFilesSeen: Set<string>) {
3785                if (emitFileName) {
3786                    const emitFilePath = toPath(emitFileName);
3787                    // Report error if the output overwrites input file
3788                    if (filesByName.has(emitFilePath)) {
3789                        let chain: DiagnosticMessageChain | undefined;
3790                        if (!options.configFilePath) {
3791                            // The program is from either an inferred project or an external project
3792                            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);
3793                        }
3794                        chain = chainDiagnosticMessages(chain, Diagnostics.Cannot_write_file_0_because_it_would_overwrite_input_file, emitFileName);
3795                        blockEmittingOfFile(emitFileName, createCompilerDiagnosticFromMessageChain(chain));
3796                    }
3797
3798                    const emitFileKey = !host.useCaseSensitiveFileNames() ? toFileNameLowerCase(emitFilePath) : emitFilePath;
3799                    // Report error if multiple files write into same file
3800                    if (emitFilesSeen.has(emitFileKey)) {
3801                        // Already seen the same emit file - report error
3802                        blockEmittingOfFile(emitFileName, createCompilerDiagnostic(Diagnostics.Cannot_write_file_0_because_it_would_be_overwritten_by_multiple_input_files, emitFileName));
3803                    }
3804                    else {
3805                        emitFilesSeen.add(emitFileKey);
3806                    }
3807                }
3808            }
3809        }
3810
3811        function createDiagnosticExplainingFile(file: SourceFile | undefined, fileProcessingReason: FileIncludeReason | undefined, diagnostic: DiagnosticMessage, args: (string | number | undefined)[] | undefined): Diagnostic {
3812            let fileIncludeReasons: DiagnosticMessageChain[] | undefined;
3813            let relatedInfo: Diagnostic[] | undefined;
3814            let locationReason = isReferencedFile(fileProcessingReason) ? fileProcessingReason : undefined;
3815            if (file) fileReasons.get(file.path)?.forEach(processReason);
3816            if (fileProcessingReason) processReason(fileProcessingReason);
3817            // If we have location and there is only one reason file is in which is the location, dont add details for file include
3818            if (locationReason && fileIncludeReasons?.length === 1) fileIncludeReasons = undefined;
3819            const location = locationReason && getReferencedFileLocation(getSourceFileByPath, locationReason);
3820            const fileIncludeReasonDetails = fileIncludeReasons && chainDiagnosticMessages(fileIncludeReasons, Diagnostics.The_file_is_in_the_program_because_Colon);
3821            const redirectInfo = file && explainIfFileIsRedirectAndImpliedFormat(file);
3822            const chain = chainDiagnosticMessages(redirectInfo ? fileIncludeReasonDetails ? [fileIncludeReasonDetails, ...redirectInfo] : redirectInfo : fileIncludeReasonDetails, diagnostic, ...args || emptyArray);
3823            return location && isReferenceFileLocation(location) ?
3824                createFileDiagnosticFromMessageChain(location.file, location.pos, location.end - location.pos, chain, relatedInfo) :
3825                createCompilerDiagnosticFromMessageChain(chain, relatedInfo);
3826
3827            function processReason(reason: FileIncludeReason) {
3828                (fileIncludeReasons ||= []).push(fileIncludeReasonToDiagnostics(program, reason));
3829                if (!locationReason && isReferencedFile(reason)) {
3830                    // Report error at first reference file or file currently in processing and dont report in related information
3831                    locationReason = reason;
3832                }
3833                else if (locationReason !== reason) {
3834                    relatedInfo = append(relatedInfo, fileIncludeReasonToRelatedInformation(reason));
3835                }
3836                // Remove fileProcessingReason if its already included in fileReasons of the program
3837                if (reason === fileProcessingReason) fileProcessingReason = undefined;
3838            }
3839        }
3840
3841        function addFilePreprocessingFileExplainingDiagnostic(file: SourceFile | undefined, fileProcessingReason: FileIncludeReason, diagnostic: DiagnosticMessage, args?: (string | number | undefined)[]) {
3842            (fileProcessingDiagnostics ||= []).push({
3843                kind: FilePreprocessingDiagnosticsKind.FilePreprocessingFileExplainingDiagnostic,
3844                file: file && file.path,
3845                fileProcessingReason,
3846                diagnostic,
3847                args
3848            });
3849        }
3850
3851        function addProgramDiagnosticExplainingFile(file: SourceFile, diagnostic: DiagnosticMessage, args?: (string | number | undefined)[]) {
3852            programDiagnostics.add(createDiagnosticExplainingFile(file, /*fileProcessingReason*/ undefined, diagnostic, args));
3853        }
3854
3855        function fileIncludeReasonToRelatedInformation(reason: FileIncludeReason): DiagnosticWithLocation | undefined {
3856            if (isReferencedFile(reason)) {
3857                const referenceLocation = getReferencedFileLocation(getSourceFileByPath, reason);
3858                let message: DiagnosticMessage;
3859                switch (reason.kind) {
3860                    case FileIncludeKind.Import:
3861                        message = Diagnostics.File_is_included_via_import_here;
3862                        break;
3863                    case FileIncludeKind.ReferenceFile:
3864                        message = Diagnostics.File_is_included_via_reference_here;
3865                        break;
3866                    case FileIncludeKind.TypeReferenceDirective:
3867                        message = Diagnostics.File_is_included_via_type_library_reference_here;
3868                        break;
3869                    case FileIncludeKind.LibReferenceDirective:
3870                        message = Diagnostics.File_is_included_via_library_reference_here;
3871                        break;
3872                    default:
3873                        Debug.assertNever(reason);
3874                }
3875                return isReferenceFileLocation(referenceLocation) ? createFileDiagnostic(
3876                    referenceLocation.file,
3877                    referenceLocation.pos,
3878                    referenceLocation.end - referenceLocation.pos,
3879                    message,
3880                ) : undefined;
3881            }
3882
3883            if (!options.configFile) return undefined;
3884            let configFileNode: Node | undefined;
3885            let message: DiagnosticMessage;
3886            switch (reason.kind) {
3887                case FileIncludeKind.RootFile:
3888                    if (!options.configFile.configFileSpecs) return undefined;
3889                    const fileName = getNormalizedAbsolutePath(rootNames[reason.index], currentDirectory);
3890                    const matchedByFiles = getMatchedFileSpec(program, fileName);
3891                    if (matchedByFiles) {
3892                        configFileNode = getTsConfigPropArrayElementValue(options.configFile, "files", matchedByFiles);
3893                        message = Diagnostics.File_is_matched_by_files_list_specified_here;
3894                        break;
3895                    }
3896                    const matchedByInclude = getMatchedIncludeSpec(program, fileName);
3897                    // Could be additional files specified as roots
3898                    if (!matchedByInclude || !isString(matchedByInclude)) return undefined;
3899                    configFileNode = getTsConfigPropArrayElementValue(options.configFile, "include", matchedByInclude);
3900                    message = Diagnostics.File_is_matched_by_include_pattern_specified_here;
3901                    break;
3902                case FileIncludeKind.SourceFromProjectReference:
3903                case FileIncludeKind.OutputFromProjectReference:
3904                    const referencedResolvedRef = Debug.checkDefined(resolvedProjectReferences?.[reason.index]);
3905                    const referenceInfo = forEachProjectReference(projectReferences, resolvedProjectReferences, (resolvedRef, parent, index) =>
3906                        resolvedRef === referencedResolvedRef ? { sourceFile: parent?.sourceFile || options.configFile!, index } : undefined
3907                    );
3908                    if (!referenceInfo) return undefined;
3909                    const { sourceFile, index } = referenceInfo;
3910                    const referencesSyntax = firstDefined(getTsConfigPropArray(sourceFile as TsConfigSourceFile, "references"),
3911                        property => isArrayLiteralExpression(property.initializer) ? property.initializer : undefined);
3912                    return referencesSyntax && referencesSyntax.elements.length > index ?
3913                        createDiagnosticForNodeInSourceFile(
3914                            sourceFile,
3915                            referencesSyntax.elements[index],
3916                            reason.kind === FileIncludeKind.OutputFromProjectReference ?
3917                                Diagnostics.File_is_output_from_referenced_project_specified_here :
3918                                Diagnostics.File_is_source_from_referenced_project_specified_here,
3919                        ) :
3920                        undefined;
3921                case FileIncludeKind.AutomaticTypeDirectiveFile:
3922                    if (!options.types) return undefined;
3923                    configFileNode = getOptionsSyntaxByArrayElementValue("types", reason.typeReference);
3924                    message = Diagnostics.File_is_entry_point_of_type_library_specified_here;
3925                    break;
3926                case FileIncludeKind.LibFile:
3927                    if (reason.index !== undefined) {
3928                        configFileNode = getOptionsSyntaxByArrayElementValue("lib", options.lib![reason.index]);
3929                        message = Diagnostics.File_is_library_specified_here;
3930                        break;
3931                    }
3932                    const target = forEachEntry(targetOptionDeclaration.type, (value, key) => value === getEmitScriptTarget(options) ? key : undefined);
3933                    configFileNode = target ? getOptionsSyntaxByValue("target", target) : undefined;
3934                    message = Diagnostics.File_is_default_library_for_target_specified_here;
3935                    break;
3936                default:
3937                    Debug.assertNever(reason);
3938            }
3939            return configFileNode && createDiagnosticForNodeInSourceFile(
3940                options.configFile,
3941                configFileNode,
3942                message,
3943            );
3944        }
3945
3946        function verifyProjectReferences() {
3947            const buildInfoPath = !options.suppressOutputPathCheck ? getTsBuildInfoEmitOutputFilePath(options) : undefined;
3948            forEachProjectReference(projectReferences, resolvedProjectReferences, (resolvedRef, parent, index) => {
3949                const ref = (parent ? parent.commandLine.projectReferences : projectReferences)![index];
3950                const parentFile = parent && parent.sourceFile as JsonSourceFile;
3951                if (!resolvedRef) {
3952                    createDiagnosticForReference(parentFile, index, Diagnostics.File_0_not_found, ref.path);
3953                    return;
3954                }
3955                const options = resolvedRef.commandLine.options;
3956                if (!options.composite || options.noEmit) {
3957                    // ok to not have composite if the current program is container only
3958                    const inputs = parent ? parent.commandLine.fileNames : rootNames;
3959                    if (inputs.length) {
3960                        if (!options.composite) createDiagnosticForReference(parentFile, index, Diagnostics.Referenced_project_0_must_have_setting_composite_Colon_true, ref.path);
3961                        if (options.noEmit) createDiagnosticForReference(parentFile, index, Diagnostics.Referenced_project_0_may_not_disable_emit, ref.path);
3962                    }
3963                }
3964                if (ref.prepend) {
3965                    const out = outFile(options);
3966                    if (out) {
3967                        if (!host.fileExists(out)) {
3968                            createDiagnosticForReference(parentFile, index, Diagnostics.Output_file_0_from_project_1_does_not_exist, out, ref.path);
3969                        }
3970                    }
3971                    else {
3972                        createDiagnosticForReference(parentFile, index, Diagnostics.Cannot_prepend_project_0_because_it_does_not_have_outFile_set, ref.path);
3973                    }
3974                }
3975                if (!parent && buildInfoPath && buildInfoPath === getTsBuildInfoEmitOutputFilePath(options)) {
3976                    createDiagnosticForReference(parentFile, index, Diagnostics.Cannot_write_file_0_because_it_will_overwrite_tsbuildinfo_file_generated_by_referenced_project_1, buildInfoPath, ref.path);
3977                    hasEmitBlockingDiagnostics.set(toPath(buildInfoPath), true);
3978                }
3979            });
3980        }
3981
3982        function createDiagnosticForOptionPathKeyValue(key: string, valueIndex: number, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number) {
3983            let needCompilerDiagnostic = true;
3984            const pathsSyntax = getOptionPathsSyntax();
3985            for (const pathProp of pathsSyntax) {
3986                if (isObjectLiteralExpression(pathProp.initializer)) {
3987                    for (const keyProps of getPropertyAssignment(pathProp.initializer, key)) {
3988                        const initializer = keyProps.initializer;
3989                        if (isArrayLiteralExpression(initializer) && initializer.elements.length > valueIndex) {
3990                            programDiagnostics.add(createDiagnosticForNodeInSourceFile(options.configFile!, initializer.elements[valueIndex], message, arg0, arg1, arg2));
3991                            needCompilerDiagnostic = false;
3992                        }
3993                    }
3994                }
3995            }
3996
3997            if (needCompilerDiagnostic) {
3998                programDiagnostics.add(createCompilerDiagnostic(message, arg0, arg1, arg2));
3999            }
4000        }
4001
4002        function createDiagnosticForOptionPaths(onKey: boolean, key: string, message: DiagnosticMessage, arg0: string | number) {
4003            let needCompilerDiagnostic = true;
4004            const pathsSyntax = getOptionPathsSyntax();
4005            for (const pathProp of pathsSyntax) {
4006                if (isObjectLiteralExpression(pathProp.initializer) &&
4007                    createOptionDiagnosticInObjectLiteralSyntax(
4008                        pathProp.initializer, onKey, key, /*key2*/ undefined,
4009                        message, arg0)) {
4010                    needCompilerDiagnostic = false;
4011                }
4012            }
4013            if (needCompilerDiagnostic) {
4014                programDiagnostics.add(createCompilerDiagnostic(message, arg0));
4015            }
4016        }
4017
4018        function getOptionsSyntaxByName(name: string) {
4019            const compilerOptionsObjectLiteralSyntax = getCompilerOptionsObjectLiteralSyntax();
4020            return compilerOptionsObjectLiteralSyntax && getPropertyAssignment(compilerOptionsObjectLiteralSyntax, name);
4021        }
4022
4023        function getOptionPathsSyntax() {
4024            return getOptionsSyntaxByName("paths") || emptyArray;
4025        }
4026
4027        function getOptionsSyntaxByValue(name: string, value: string) {
4028            const syntaxByName = getOptionsSyntaxByName(name);
4029            return syntaxByName && firstDefined(syntaxByName, property => isStringLiteral(property.initializer) && property.initializer.text === value ? property.initializer : undefined);
4030        }
4031
4032        function getOptionsSyntaxByArrayElementValue(name: string, value: string) {
4033            const compilerOptionsObjectLiteralSyntax = getCompilerOptionsObjectLiteralSyntax();
4034            return compilerOptionsObjectLiteralSyntax && getPropertyArrayElementValue(compilerOptionsObjectLiteralSyntax, name, value);
4035        }
4036
4037        function createDiagnosticForOptionName(message: DiagnosticMessage, option1: string, option2?: string, option3?: string) {
4038            createDiagnosticForOption(/*onKey*/ true, option1, option2, message, option1, option2, option3);
4039        }
4040
4041        function createOptionValueDiagnostic(option1: string, message: DiagnosticMessage, arg0?: string, arg1?: string) {
4042            createDiagnosticForOption(/*onKey*/ false, option1, /*option2*/ undefined, message, arg0, arg1);
4043        }
4044
4045        function createDiagnosticForReference(sourceFile: JsonSourceFile | undefined, index: number, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number) {
4046            const referencesSyntax = firstDefined(getTsConfigPropArray(sourceFile || options.configFile, "references"),
4047                property => isArrayLiteralExpression(property.initializer) ? property.initializer : undefined);
4048            if (referencesSyntax && referencesSyntax.elements.length > index) {
4049                programDiagnostics.add(createDiagnosticForNodeInSourceFile(sourceFile || options.configFile!, referencesSyntax.elements[index], message, arg0, arg1));
4050            }
4051            else {
4052                programDiagnostics.add(createCompilerDiagnostic(message, arg0, arg1));
4053            }
4054        }
4055
4056        function createDiagnosticForOption(onKey: boolean, option1: string, option2: string | undefined, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number) {
4057            const compilerOptionsObjectLiteralSyntax = getCompilerOptionsObjectLiteralSyntax();
4058            const needCompilerDiagnostic = !compilerOptionsObjectLiteralSyntax ||
4059                !createOptionDiagnosticInObjectLiteralSyntax(compilerOptionsObjectLiteralSyntax, onKey, option1, option2, message, arg0, arg1, arg2);
4060
4061            if (needCompilerDiagnostic) {
4062                programDiagnostics.add(createCompilerDiagnostic(message, arg0, arg1, arg2));
4063            }
4064        }
4065
4066        function getCompilerOptionsObjectLiteralSyntax() {
4067            if (_compilerOptionsObjectLiteralSyntax === undefined) {
4068                _compilerOptionsObjectLiteralSyntax = false;
4069                const jsonObjectLiteral = getTsConfigObjectLiteralExpression(options.configFile);
4070                if (jsonObjectLiteral) {
4071                    for (const prop of getPropertyAssignment(jsonObjectLiteral, "compilerOptions")) {
4072                        if (isObjectLiteralExpression(prop.initializer)) {
4073                            _compilerOptionsObjectLiteralSyntax = prop.initializer;
4074                            break;
4075                        }
4076                    }
4077                }
4078            }
4079            return _compilerOptionsObjectLiteralSyntax || undefined;
4080        }
4081
4082        function createOptionDiagnosticInObjectLiteralSyntax(objectLiteral: ObjectLiteralExpression, onKey: boolean, key1: string, key2: string | undefined, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number): boolean {
4083            const props = getPropertyAssignment(objectLiteral, key1, key2);
4084            for (const prop of props) {
4085                programDiagnostics.add(createDiagnosticForNodeInSourceFile(options.configFile!, onKey ? prop.name : prop.initializer, message, arg0, arg1, arg2));
4086            }
4087            return !!props.length;
4088        }
4089
4090        function blockEmittingOfFile(emitFileName: string, diag: Diagnostic) {
4091            hasEmitBlockingDiagnostics.set(toPath(emitFileName), true);
4092            programDiagnostics.add(diag);
4093        }
4094
4095        function isEmittedFile(file: string): boolean {
4096            if (options.noEmit) {
4097                return false;
4098            }
4099
4100            // If this is source file, its not emitted file
4101            const filePath = toPath(file);
4102            if (getSourceFileByPath(filePath)) {
4103                return false;
4104            }
4105
4106            // If options have --outFile or --out just check that
4107            const out = outFile(options);
4108            if (out) {
4109                return isSameFile(filePath, out) || isSameFile(filePath, removeFileExtension(out) + Extension.Dts);
4110            }
4111
4112            // If declarationDir is specified, return if its a file in that directory
4113            if (options.declarationDir && containsPath(options.declarationDir, filePath, currentDirectory, !host.useCaseSensitiveFileNames())) {
4114                return true;
4115            }
4116
4117            // If --outDir, check if file is in that directory
4118            if (options.outDir) {
4119                return containsPath(options.outDir, filePath, currentDirectory, !host.useCaseSensitiveFileNames());
4120            }
4121
4122            if (fileExtensionIsOneOf(filePath, supportedJSExtensionsFlat) || isDeclarationFileName(filePath)) {
4123                // Otherwise just check if sourceFile with the name exists
4124                const filePathWithoutExtension = removeFileExtension(filePath);
4125                return !!getSourceFileByPath((filePathWithoutExtension + Extension.Ts) as Path) ||
4126                    !!getSourceFileByPath((filePathWithoutExtension + Extension.Tsx) as Path);
4127            }
4128            return false;
4129        }
4130
4131        function isSameFile(file1: string, file2: string) {
4132            return comparePaths(file1, file2, currentDirectory, !host.useCaseSensitiveFileNames()) === Comparison.EqualTo;
4133        }
4134
4135        function getSymlinkCache(): SymlinkCache {
4136            if (host.getSymlinkCache) {
4137                return host.getSymlinkCache();
4138            }
4139            if (!symlinks) {
4140                symlinks = createSymlinkCache(currentDirectory, getCanonicalFileName, isOhpm(options.packageManagerType));
4141            }
4142            if (files && resolvedTypeReferenceDirectives && !symlinks.hasProcessedResolutions()) {
4143                symlinks.setSymlinksFromResolutions(files, resolvedTypeReferenceDirectives);
4144            }
4145            return symlinks;
4146        }
4147    }
4148
4149    interface HostForUseSourceOfProjectReferenceRedirect {
4150        compilerHost: CompilerHost;
4151        getSymlinkCache: () => SymlinkCache;
4152        useSourceOfProjectReferenceRedirect: boolean;
4153        toPath(fileName: string): Path;
4154        getResolvedProjectReferences(): readonly (ResolvedProjectReference | undefined)[] | undefined;
4155        getSourceOfProjectReferenceRedirect(path: Path): SourceOfProjectReferenceRedirect | undefined;
4156        forEachResolvedProjectReference<T>(cb: (resolvedProjectReference: ResolvedProjectReference) => T | undefined): T | undefined;
4157        options?: CompilerOptions;
4158    }
4159
4160    function updateHostForUseSourceOfProjectReferenceRedirect(host: HostForUseSourceOfProjectReferenceRedirect) {
4161        let setOfDeclarationDirectories: Set<Path> | undefined;
4162        const originalFileExists = host.compilerHost.fileExists;
4163        const originalDirectoryExists = host.compilerHost.directoryExists;
4164        const originalGetDirectories = host.compilerHost.getDirectories;
4165        const originalRealpath = host.compilerHost.realpath;
4166
4167        if (!host.useSourceOfProjectReferenceRedirect) return { onProgramCreateComplete: noop, fileExists };
4168
4169        host.compilerHost.fileExists = fileExists;
4170
4171        let directoryExists;
4172        if (originalDirectoryExists) {
4173            // This implementation of directoryExists checks if the directory being requested is
4174            // directory of .d.ts file for the referenced Project.
4175            // If it is it returns true irrespective of whether that directory exists on host
4176            directoryExists = host.compilerHost.directoryExists = path => {
4177                if (originalDirectoryExists.call(host.compilerHost, path)) {
4178                    handleDirectoryCouldBeSymlink(path);
4179                    return true;
4180                }
4181
4182                if (!host.getResolvedProjectReferences()) return false;
4183
4184                if (!setOfDeclarationDirectories) {
4185                    setOfDeclarationDirectories = new Set();
4186                    host.forEachResolvedProjectReference(ref => {
4187                        const out = outFile(ref.commandLine.options);
4188                        if (out) {
4189                            setOfDeclarationDirectories!.add(getDirectoryPath(host.toPath(out)));
4190                        }
4191                        else {
4192                            // Set declaration's in different locations only, if they are next to source the directory present doesnt change
4193                            const declarationDir = ref.commandLine.options.declarationDir || ref.commandLine.options.outDir;
4194                            if (declarationDir) {
4195                                setOfDeclarationDirectories!.add(host.toPath(declarationDir));
4196                            }
4197                        }
4198                    });
4199                }
4200
4201                return fileOrDirectoryExistsUsingSource(path, /*isFile*/ false);
4202            };
4203        }
4204
4205        if (originalGetDirectories) {
4206            // Call getDirectories only if directory actually present on the host
4207            // This is needed to ensure that we arent getting directories that we fake about presence for
4208            host.compilerHost.getDirectories = path =>
4209                !host.getResolvedProjectReferences() || (originalDirectoryExists && originalDirectoryExists.call(host.compilerHost, path)) ?
4210                    originalGetDirectories.call(host.compilerHost, path) :
4211                    [];
4212        }
4213
4214        // This is something we keep for life time of the host
4215        if (originalRealpath) {
4216            host.compilerHost.realpath = s =>
4217                host.getSymlinkCache().getSymlinkedFiles()?.get(host.toPath(s)) ||
4218                originalRealpath.call(host.compilerHost, s);
4219        }
4220
4221        return { onProgramCreateComplete, fileExists, directoryExists };
4222
4223        function onProgramCreateComplete() {
4224            host.compilerHost.fileExists = originalFileExists;
4225            host.compilerHost.directoryExists = originalDirectoryExists;
4226            host.compilerHost.getDirectories = originalGetDirectories;
4227            // DO not revert realpath as it could be used later
4228        }
4229
4230        // This implementation of fileExists checks if the file being requested is
4231        // .d.ts file for the referenced Project.
4232        // If it is it returns true irrespective of whether that file exists on host
4233        function fileExists(file: string) {
4234            if (originalFileExists.call(host.compilerHost, file)) return true;
4235            if (!host.getResolvedProjectReferences()) return false;
4236            if (!isDeclarationFileName(file)) return false;
4237
4238            // Project references go to source file instead of .d.ts file
4239            return fileOrDirectoryExistsUsingSource(file, /*isFile*/ true);
4240        }
4241
4242        function fileExistsIfProjectReferenceDts(file: string) {
4243            const source = host.getSourceOfProjectReferenceRedirect(host.toPath(file));
4244            return source !== undefined ?
4245                isString(source) ? originalFileExists.call(host.compilerHost, source) as boolean : true :
4246                undefined;
4247        }
4248
4249        function directoryExistsIfProjectReferenceDeclDir(dir: string) {
4250            const dirPath = host.toPath(dir);
4251            const dirPathWithTrailingDirectorySeparator = `${dirPath}${directorySeparator}`;
4252            return forEachKey(
4253                setOfDeclarationDirectories!,
4254                declDirPath => dirPath === declDirPath ||
4255                    // Any parent directory of declaration dir
4256                    startsWith(declDirPath, dirPathWithTrailingDirectorySeparator) ||
4257                    // Any directory inside declaration dir
4258                    startsWith(dirPath, `${declDirPath}/`)
4259            );
4260        }
4261
4262        function handleDirectoryCouldBeSymlink(directory: string) {
4263            if (!host.getResolvedProjectReferences() || containsIgnoredPath(directory)) return;
4264
4265            // Because we already watch node_modules or oh_modules, handle symlinks in there
4266            const modulesPathPart = getModulePathPartByPMType(host.options?.packageManagerType);
4267            if (!originalRealpath || !stringContains(directory, modulesPathPart)) return;
4268            const symlinkCache = host.getSymlinkCache();
4269            const directoryPath = ensureTrailingDirectorySeparator(host.toPath(directory));
4270            if (symlinkCache.getSymlinkedDirectories()?.has(directoryPath)) return;
4271
4272            const real = normalizePath(originalRealpath.call(host.compilerHost, directory));
4273            let realPath: Path;
4274            if (real === directory ||
4275                (realPath = ensureTrailingDirectorySeparator(host.toPath(real))) === directoryPath) {
4276                // not symlinked
4277                symlinkCache.setSymlinkedDirectory(directoryPath, false);
4278                return;
4279            }
4280
4281            symlinkCache.setSymlinkedDirectory(directory, {
4282                real: ensureTrailingDirectorySeparator(real),
4283                realPath
4284            });
4285        }
4286
4287        function fileOrDirectoryExistsUsingSource(fileOrDirectory: string, isFile: boolean): boolean {
4288            const fileOrDirectoryExistsUsingSource = isFile ?
4289                (file: string) => fileExistsIfProjectReferenceDts(file) :
4290                (dir: string) => directoryExistsIfProjectReferenceDeclDir(dir);
4291            // Check current directory or file
4292            const result = fileOrDirectoryExistsUsingSource(fileOrDirectory);
4293            if (result !== undefined) return result;
4294
4295            const symlinkCache = host.getSymlinkCache();
4296            const symlinkedDirectories = symlinkCache.getSymlinkedDirectories();
4297            if (!symlinkedDirectories) return false;
4298            const fileOrDirectoryPath = host.toPath(fileOrDirectory);
4299            const modulesPathPart = getModulePathPartByPMType(host.options?.packageManagerType);
4300            if (!stringContains(fileOrDirectoryPath, modulesPathPart)) return false;
4301            if (isFile && symlinkCache.getSymlinkedFiles()?.has(fileOrDirectoryPath)) return true;
4302
4303            // If it contains node_modules or oh_modules check if its one of the symlinked path we know of
4304            return firstDefinedIterator(
4305                symlinkedDirectories.entries(),
4306                ([directoryPath, symlinkedDirectory]) => {
4307                    if (!symlinkedDirectory || !startsWith(fileOrDirectoryPath, directoryPath)) return undefined;
4308                    const result = fileOrDirectoryExistsUsingSource(fileOrDirectoryPath.replace(directoryPath, symlinkedDirectory.realPath));
4309                    if (isFile && result) {
4310                        // Store the real path for the file'
4311                        const absolutePath = getNormalizedAbsolutePath(fileOrDirectory, host.compilerHost.getCurrentDirectory());
4312                        symlinkCache.setSymlinkedFile(
4313                            fileOrDirectoryPath,
4314                            `${symlinkedDirectory.real}${absolutePath.replace(new RegExp(directoryPath, "i"), "")}`
4315                        );
4316                    }
4317                    return result;
4318                }
4319            ) || false;
4320        }
4321    }
4322
4323    /*@internal*/
4324    export const emitSkippedWithNoDiagnostics: EmitResult = { diagnostics: emptyArray, sourceMaps: undefined, emittedFiles: undefined, emitSkipped: true };
4325
4326    /*@internal*/
4327    export function handleNoEmitOptions<T extends BuilderProgram>(
4328        program: Program | T,
4329        sourceFile: SourceFile | undefined,
4330        writeFile: WriteFileCallback | undefined,
4331        cancellationToken: CancellationToken | undefined
4332    ): EmitResult | undefined {
4333        const options = program.getCompilerOptions();
4334        if (options.noEmit) {
4335            // Cache the semantic diagnostics
4336            program.getSemanticDiagnostics(sourceFile, cancellationToken);
4337            return sourceFile || outFile(options) ?
4338                emitSkippedWithNoDiagnostics :
4339                program.emitBuildInfo(writeFile, cancellationToken);
4340        }
4341
4342        // If the noEmitOnError flag is set, then check if we have any errors so far.  If so,
4343        // immediately bail out.  Note that we pass 'undefined' for 'sourceFile' so that we
4344        // get any preEmit diagnostics, not just the ones
4345        if (!options.noEmitOnError) return undefined;
4346        let diagnostics: readonly Diagnostic[] = [
4347            ...program.getOptionsDiagnostics(cancellationToken),
4348            ...program.getSyntacticDiagnostics(sourceFile, cancellationToken),
4349            ...program.getGlobalDiagnostics(cancellationToken),
4350            ...program.getSemanticDiagnostics(sourceFile, cancellationToken)
4351        ];
4352
4353        if (diagnostics.length === 0 && getEmitDeclarations(program.getCompilerOptions())) {
4354            diagnostics = program.getDeclarationDiagnostics(/*sourceFile*/ undefined, cancellationToken);
4355        }
4356
4357        if (!diagnostics.length) return undefined;
4358        let emittedFiles: string[] | undefined;
4359        if (!sourceFile && !outFile(options)) {
4360            const emitResult = program.emitBuildInfo(writeFile, cancellationToken);
4361            if (emitResult.diagnostics) diagnostics = [...diagnostics, ...emitResult.diagnostics];
4362            emittedFiles = emitResult.emittedFiles;
4363        }
4364        return { diagnostics, sourceMaps: undefined, emittedFiles, emitSkipped: true };
4365    }
4366
4367    /*@internal*/
4368    export function filterSemanticDiagnostics(diagnostic: readonly Diagnostic[], option: CompilerOptions): readonly Diagnostic[] {
4369        return filter(diagnostic, d => !d.skippedOn || !option[d.skippedOn]);
4370    }
4371
4372    /*@internal*/
4373    interface CompilerHostLike {
4374        useCaseSensitiveFileNames(): boolean;
4375        getCurrentDirectory(): string;
4376        fileExists(fileName: string): boolean;
4377        readFile(fileName: string): string | undefined;
4378        readDirectory?(rootDir: string, extensions: readonly string[], excludes: readonly string[] | undefined, includes: readonly string[], depth?: number): string[];
4379        trace?(s: string): void;
4380        onUnRecoverableConfigFileDiagnostic?: DiagnosticReporter;
4381    }
4382
4383    /* @internal */
4384    export function parseConfigHostFromCompilerHostLike(host: CompilerHostLike, directoryStructureHost: DirectoryStructureHost = host): ParseConfigFileHost {
4385        return {
4386            fileExists: f => directoryStructureHost.fileExists(f),
4387            readDirectory(root, extensions, excludes, includes, depth) {
4388                Debug.assertIsDefined(directoryStructureHost.readDirectory, "'CompilerHost.readDirectory' must be implemented to correctly process 'projectReferences'");
4389                return directoryStructureHost.readDirectory(root, extensions, excludes, includes, depth);
4390            },
4391            readFile: f => directoryStructureHost.readFile(f),
4392            useCaseSensitiveFileNames: host.useCaseSensitiveFileNames(),
4393            getCurrentDirectory: () => host.getCurrentDirectory(),
4394            onUnRecoverableConfigFileDiagnostic: host.onUnRecoverableConfigFileDiagnostic || returnUndefined,
4395            trace: host.trace ? (s) => host.trace!(s) : undefined
4396        };
4397    }
4398
4399    // For backward compatibility
4400    /** @deprecated */ export interface ResolveProjectReferencePathHost {
4401        fileExists(fileName: string): boolean;
4402    }
4403
4404    /* @internal */
4405    export function createPrependNodes(projectReferences: readonly ProjectReference[] | undefined, getCommandLine: (ref: ProjectReference, index: number) => ParsedCommandLine | undefined, readFile: (path: string) => string | undefined) {
4406        if (!projectReferences) return emptyArray;
4407        let nodes: InputFiles[] | undefined;
4408        for (let i = 0; i < projectReferences.length; i++) {
4409            const ref = projectReferences[i];
4410            const resolvedRefOpts = getCommandLine(ref, i);
4411            if (ref.prepend && resolvedRefOpts && resolvedRefOpts.options) {
4412                const out = outFile(resolvedRefOpts.options);
4413                // Upstream project didn't have outFile set -- skip (error will have been issued earlier)
4414                if (!out) continue;
4415
4416                const { jsFilePath, sourceMapFilePath, declarationFilePath, declarationMapPath, buildInfoPath } = getOutputPathsForBundle(resolvedRefOpts.options, /*forceDtsPaths*/ true);
4417                const node = createInputFiles(readFile, jsFilePath!, sourceMapFilePath, declarationFilePath!, declarationMapPath, buildInfoPath);
4418                (nodes || (nodes = [])).push(node);
4419            }
4420        }
4421        return nodes || emptyArray;
4422    }
4423    /**
4424     * Returns the target config filename of a project reference.
4425     * Note: The file might not exist.
4426     */
4427    export function resolveProjectReferencePath(ref: ProjectReference): ResolvedConfigFileName;
4428    /** @deprecated */ export function resolveProjectReferencePath(host: ResolveProjectReferencePathHost, ref: ProjectReference): ResolvedConfigFileName;
4429    export function resolveProjectReferencePath(hostOrRef: ResolveProjectReferencePathHost | ProjectReference, ref?: ProjectReference): ResolvedConfigFileName {
4430        const passedInRef = ref ? ref : hostOrRef as ProjectReference;
4431        return resolveConfigFileProjectName(passedInRef.path);
4432    }
4433
4434    /* @internal */
4435    /**
4436     * Returns a DiagnosticMessage if we won't include a resolved module due to its extension.
4437     * The DiagnosticMessage's parameters are the imported module name, and the filename it resolved to.
4438     * This returns a diagnostic even if the module will be an untyped module.
4439     */
4440    export function getResolutionDiagnostic(options: CompilerOptions, { extension }: ResolvedModuleFull): DiagnosticMessage | undefined {
4441        switch (extension) {
4442            case Extension.Ts:
4443            case Extension.Dts:
4444            case Extension.Ets:
4445            case Extension.Dets:
4446                // These are always allowed.
4447                return undefined;
4448            case Extension.Tsx:
4449                return needJsx();
4450            case Extension.Jsx:
4451                return needJsx() || needAllowJs();
4452            case Extension.Js:
4453                return needAllowJs();
4454            case Extension.Json:
4455                return needResolveJsonModule();
4456        }
4457
4458        function needJsx() {
4459            return options.jsx ? undefined : Diagnostics.Module_0_was_resolved_to_1_but_jsx_is_not_set;
4460        }
4461        function needAllowJs() {
4462            return getAllowJSCompilerOption(options) || !getStrictOptionValue(options, "noImplicitAny") ? undefined : Diagnostics.Could_not_find_a_declaration_file_for_module_0_1_implicitly_has_an_any_type;
4463        }
4464        function needResolveJsonModule() {
4465            return options.resolveJsonModule ? undefined : Diagnostics.Module_0_was_resolved_to_1_but_resolveJsonModule_is_not_used;
4466        }
4467    }
4468
4469    function getModuleNames({ imports, moduleAugmentations }: SourceFile): string[] {
4470        const res = imports.map(i => i.text);
4471        for (const aug of moduleAugmentations) {
4472            if (aug.kind === SyntaxKind.StringLiteral) {
4473                res.push(aug.text);
4474            }
4475            // Do nothing if it's an Identifier; we don't need to do module resolution for `declare global`.
4476        }
4477        return res;
4478    }
4479
4480    /* @internal */
4481    export function getModuleNameStringLiteralAt({ imports, moduleAugmentations }: SourceFileImportsList, index: number): StringLiteralLike {
4482        if (index < imports.length) return imports[index];
4483        let augIndex = imports.length;
4484        for (const aug of moduleAugmentations) {
4485            if (aug.kind === SyntaxKind.StringLiteral) {
4486                if (index === augIndex) return aug;
4487                augIndex++;
4488            }
4489            // Do nothing if it's an Identifier; we don't need to do module resolution for `declare global`.
4490        }
4491        Debug.fail("should never ask for module name at index higher than possible module name");
4492    }
4493}
4494