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