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