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