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