mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-04 03:09:39 -06:00
Skip verifyCompilerOptions when possible on program updates (#60754)
Co-authored-by: Daniel Rosenwasser <DanielRosenwasser@users.noreply.github.com>
This commit is contained in:
parent
df54a3d6b4
commit
cbac1ddfc7
@ -61,6 +61,7 @@ export * from "../transformer.js";
|
||||
export * from "../emitter.js";
|
||||
export * from "../watchUtilities.js";
|
||||
export * from "../program.js";
|
||||
export * from "../programDiagnostics.js";
|
||||
export * from "../builderStatePublic.js";
|
||||
export * from "../builderState.js";
|
||||
export * from "../builder.js";
|
||||
|
||||
@ -33,17 +33,16 @@ import {
|
||||
createCommentDirectivesMap,
|
||||
createCompilerDiagnostic,
|
||||
createCompilerDiagnosticFromMessageChain,
|
||||
createDiagnosticCollection,
|
||||
createDiagnosticForNodeFromMessageChain,
|
||||
createDiagnosticForNodeInSourceFile,
|
||||
createDiagnosticForRange,
|
||||
createFileDiagnostic,
|
||||
createFileDiagnosticFromMessageChain,
|
||||
createGetCanonicalFileName,
|
||||
createModeAwareCache,
|
||||
createModeAwareCacheKey,
|
||||
createModuleResolutionCache,
|
||||
createMultiMap,
|
||||
createProgramDiagnostics,
|
||||
CreateProgramOptions,
|
||||
createSourceFile,
|
||||
CreateSourceFileOptions,
|
||||
@ -75,7 +74,6 @@ import {
|
||||
equateStringsCaseInsensitive,
|
||||
equateStringsCaseSensitive,
|
||||
exclusivelyPrefixedNodeCoreModules,
|
||||
explainIfFileIsRedirectAndImpliedFormat,
|
||||
ExportAssignment,
|
||||
ExportDeclaration,
|
||||
Extension,
|
||||
@ -86,10 +84,7 @@ import {
|
||||
fileExtensionIsOneOf,
|
||||
FileIncludeKind,
|
||||
FileIncludeReason,
|
||||
fileIncludeReasonToDiagnostics,
|
||||
FilePreprocessingDiagnostics,
|
||||
FilePreprocessingDiagnosticsKind,
|
||||
FilePreprocessingLibReferenceDiagnostic,
|
||||
FileReference,
|
||||
filter,
|
||||
find,
|
||||
@ -104,6 +99,8 @@ import {
|
||||
forEachEmittedFile,
|
||||
forEachEntry,
|
||||
forEachKey,
|
||||
forEachOptionsSyntaxByName,
|
||||
forEachProjectReference,
|
||||
forEachPropertyAssignment,
|
||||
forEachResolvedProjectReference as ts_forEachResolvedProjectReference,
|
||||
forEachTsConfigPropArray,
|
||||
@ -126,11 +123,9 @@ import {
|
||||
getIsolatedModules,
|
||||
getJSXImplicitImportBase,
|
||||
getJSXRuntimeImport,
|
||||
getLibFileNameFromLibReference,
|
||||
getLineAndCharacterOfPosition,
|
||||
getLineStarts,
|
||||
getMatchedFileSpec,
|
||||
getMatchedIncludeSpec,
|
||||
getNameOfScriptTarget,
|
||||
getNewLineCharacter,
|
||||
getNormalizedAbsolutePath,
|
||||
getNormalizedAbsolutePathWithoutRoot,
|
||||
@ -139,14 +134,12 @@ import {
|
||||
getPackageScopeForPath,
|
||||
getPathFromPathComponents,
|
||||
getPositionOfLineAndCharacter,
|
||||
getPropertyArrayElementValue,
|
||||
getResolvedModuleFromResolution,
|
||||
getResolvedTypeReferenceDirectiveFromResolution,
|
||||
getResolveJsonModule,
|
||||
getRootLength,
|
||||
getSetExternalModuleIndicator,
|
||||
getSourceFileOfNode,
|
||||
getSpellingSuggestion,
|
||||
getStrictOptionValue,
|
||||
getSupportedExtensions,
|
||||
getSupportedExtensionsWithJsonIfResolveJsonModule,
|
||||
@ -155,7 +148,6 @@ import {
|
||||
getTransformers,
|
||||
getTsBuildInfoEmitOutputFilePath,
|
||||
getTsConfigObjectLiteralExpression,
|
||||
getTsConfigPropArrayElementValue,
|
||||
getTypesPackageName,
|
||||
HasChangedAutomaticTypeDirectiveNames,
|
||||
hasChangesInResolutions,
|
||||
@ -215,7 +207,6 @@ import {
|
||||
JsonSourceFile,
|
||||
JsxEmit,
|
||||
length,
|
||||
libMap,
|
||||
LibResolution,
|
||||
libs,
|
||||
mapDefined,
|
||||
@ -246,6 +237,7 @@ import {
|
||||
noTransformers,
|
||||
ObjectLiteralExpression,
|
||||
OperationCanceledException,
|
||||
optionDeclarations,
|
||||
optionsHaveChanges,
|
||||
PackageId,
|
||||
packageIdToPackageName,
|
||||
@ -317,7 +309,6 @@ import {
|
||||
trace,
|
||||
tracing,
|
||||
tryCast,
|
||||
TsConfigSourceFile,
|
||||
TypeChecker,
|
||||
typeDirectiveIsEqualTo,
|
||||
TypeReferenceDirectiveResolutionCache,
|
||||
@ -1142,60 +1133,6 @@ export function loadWithModeAwareCache<Entry, SourceFile, ResolutionCache, Resol
|
||||
return resolutions;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function forEachResolvedProjectReference<T>(
|
||||
resolvedProjectReferences: readonly (ResolvedProjectReference | undefined)[] | undefined,
|
||||
cb: (resolvedProjectReference: ResolvedProjectReference, parent: ResolvedProjectReference | undefined) => T | undefined,
|
||||
): T | undefined {
|
||||
return forEachProjectReference(
|
||||
/*projectReferences*/ undefined,
|
||||
resolvedProjectReferences,
|
||||
(resolvedRef, parent) => resolvedRef && cb(resolvedRef, parent),
|
||||
);
|
||||
}
|
||||
|
||||
function forEachProjectReference<T>(
|
||||
projectReferences: readonly ProjectReference[] | undefined,
|
||||
resolvedProjectReferences: readonly (ResolvedProjectReference | undefined)[] | undefined,
|
||||
cbResolvedRef: (resolvedRef: ResolvedProjectReference | undefined, parent: ResolvedProjectReference | undefined, index: number) => T | undefined,
|
||||
cbRef?: (projectReferences: readonly ProjectReference[] | undefined, parent: ResolvedProjectReference | undefined) => T | undefined,
|
||||
): T | undefined {
|
||||
let seenResolvedRefs: Set<Path> | undefined;
|
||||
return worker(projectReferences, resolvedProjectReferences, /*parent*/ undefined);
|
||||
|
||||
function worker(
|
||||
projectReferences: readonly ProjectReference[] | undefined,
|
||||
resolvedProjectReferences: readonly (ResolvedProjectReference | undefined)[] | undefined,
|
||||
parent: ResolvedProjectReference | undefined,
|
||||
): T | undefined {
|
||||
// Visit project references first
|
||||
if (cbRef) {
|
||||
const result = cbRef(projectReferences, parent);
|
||||
if (result) return result;
|
||||
}
|
||||
let skipChildren: Set<ResolvedProjectReference> | undefined;
|
||||
return forEach(
|
||||
resolvedProjectReferences,
|
||||
(resolvedRef, index) => {
|
||||
if (resolvedRef && seenResolvedRefs?.has(resolvedRef.sourceFile.path)) {
|
||||
(skipChildren ??= new Set()).add(resolvedRef);
|
||||
// ignore recursives
|
||||
return undefined;
|
||||
}
|
||||
const result = cbResolvedRef(resolvedRef, parent, index);
|
||||
if (result || !resolvedRef) return result;
|
||||
(seenResolvedRefs ||= new Set()).add(resolvedRef.sourceFile.path);
|
||||
},
|
||||
) || forEach(
|
||||
resolvedProjectReferences,
|
||||
resolvedRef =>
|
||||
resolvedRef && !skipChildren?.has(resolvedRef) ?
|
||||
worker(resolvedRef.commandLine.projectReferences, resolvedRef.references, resolvedRef) :
|
||||
undefined,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export const inferredTypesContainingFile = "__inferred type names__.ts";
|
||||
|
||||
@ -1220,15 +1157,6 @@ export function getLibraryNameFromLibFileName(libFileName: string): string {
|
||||
return "@typescript/lib-" + path;
|
||||
}
|
||||
|
||||
function getLibNameFromLibReference(libReference: FileReference) {
|
||||
return toFileNameLowerCase(libReference.fileName);
|
||||
}
|
||||
|
||||
function getLibFileNameFromLibReference(libReference: FileReference) {
|
||||
const libName = getLibNameFromLibReference(libReference);
|
||||
return libMap.get(libName);
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function isReferencedFile(reason: FileIncludeReason | undefined): reason is ReferencedFile {
|
||||
switch (reason?.kind) {
|
||||
@ -1536,16 +1464,6 @@ const plainJSErrors = new Set<number>([
|
||||
Diagnostics.This_condition_will_always_return_0_since_JavaScript_compares_objects_by_reference_not_value.code,
|
||||
]);
|
||||
|
||||
interface LazyProgramDiagnosticExplainingFile {
|
||||
file: SourceFile;
|
||||
diagnostic: DiagnosticMessage;
|
||||
args: DiagnosticArguments;
|
||||
}
|
||||
interface FileReasonToChainCache {
|
||||
fileIncludeReasonDetails: DiagnosticMessageChain | undefined;
|
||||
redirectInfo: DiagnosticMessageChain[] | undefined;
|
||||
details?: DiagnosticMessageChain[];
|
||||
}
|
||||
/**
|
||||
* Determine if source file needs to be re-created even if its text hasn't changed
|
||||
*/
|
||||
@ -1611,17 +1529,13 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
|
||||
let processingOtherFiles: SourceFile[] | undefined;
|
||||
let files: SourceFile[];
|
||||
let symlinks: SymlinkCache | undefined;
|
||||
let commonSourceDirectory: string;
|
||||
let typeChecker: TypeChecker;
|
||||
let classifiableNames: Set<__String>;
|
||||
let fileReasons = createMultiMap<Path, FileIncludeReason>();
|
||||
let filesWithReferencesProcessed: Set<Path> | undefined;
|
||||
let fileReasonsToChain: Map<Path, FileReasonToChainCache> | undefined;
|
||||
let reasonToRelatedInfo: Map<FileIncludeReason, DiagnosticWithLocation | false> | undefined;
|
||||
let cachedBindAndCheckDiagnosticsForFile: Map<Path, readonly Diagnostic[]> | undefined;
|
||||
let cachedDeclarationDiagnosticsForFile: Map<Path, readonly DiagnosticWithLocation[]> | undefined;
|
||||
const programDiagnostics = createProgramDiagnostics(getCompilerOptionsObjectLiteralSyntax);
|
||||
|
||||
let fileProcessingDiagnostics: FilePreprocessingDiagnostics[] | undefined;
|
||||
let automaticTypeDirectiveNames: string[] | undefined;
|
||||
let automaticTypeDirectiveResolutions: ModeAwareCache<ResolvedTypeReferenceDirectiveWithFailedLookupLocations>;
|
||||
|
||||
@ -1661,13 +1575,8 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
|
||||
let skipDefaultLib = options.noLib;
|
||||
const getDefaultLibraryFileName = memoize(() => host.getDefaultLibFileName(options));
|
||||
const defaultLibraryPath = host.getDefaultLibLocation ? host.getDefaultLibLocation() : getDirectoryPath(getDefaultLibraryFileName());
|
||||
/**
|
||||
* Diagnostics for the program
|
||||
* Only add diagnostics directly if it always would be done irrespective of program structure reuse.
|
||||
* Otherwise fileProcessingDiagnostics is correct locations so that the diagnostics can be reported in all structure use scenarios
|
||||
*/
|
||||
const programDiagnostics = createDiagnosticCollection();
|
||||
let lazyProgramDiagnosticExplainingFile: LazyProgramDiagnosticExplainingFile[] | undefined = [];
|
||||
|
||||
let skipVerifyCompilerOptions = false;
|
||||
const currentDirectory = host.getCurrentDirectory();
|
||||
const supportedExtensions = getSupportedExtensions(options);
|
||||
const supportedExtensionsWithJsonIfResolveJsonModule = getSupportedExtensionsWithJsonIfResolveJsonModule(options, supportedExtensions);
|
||||
@ -1990,7 +1899,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
|
||||
getTypeCount: () => getTypeChecker().getTypeCount(),
|
||||
getInstantiationCount: () => getTypeChecker().getInstantiationCount(),
|
||||
getRelationCacheSizes: () => getTypeChecker().getRelationCacheSizes(),
|
||||
getFileProcessingDiagnostics: () => fileProcessingDiagnostics,
|
||||
getFileProcessingDiagnostics: () => programDiagnostics.getFileProcessingDiagnostics(),
|
||||
getAutomaticTypeDirectiveNames: () => automaticTypeDirectiveNames!,
|
||||
getAutomaticTypeDirectiveResolutions: () => automaticTypeDirectiveResolutions,
|
||||
isSourceFileFromExternalLibrary,
|
||||
@ -2006,6 +1915,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
|
||||
resolvedModules,
|
||||
resolvedTypeReferenceDirectiveNames,
|
||||
resolvedLibReferences,
|
||||
getProgramDiagnosticsContainer: () => programDiagnostics,
|
||||
getResolvedModule,
|
||||
getResolvedModuleFromModuleSpecifier,
|
||||
getResolvedTypeReferenceDirective,
|
||||
@ -2038,7 +1948,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
|
||||
realpath: host.realpath?.bind(host),
|
||||
useCaseSensitiveFileNames: () => host.useCaseSensitiveFileNames(),
|
||||
getCanonicalFileName,
|
||||
getFileIncludeReasons: () => fileReasons,
|
||||
getFileIncludeReasons: () => programDiagnostics.getFileReasons(),
|
||||
structureIsReused,
|
||||
writeFile,
|
||||
getGlobalTypingsCacheLocation: maybeBind(host, host.getGlobalTypingsCacheLocation),
|
||||
@ -2046,63 +1956,15 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
|
||||
|
||||
onProgramCreateComplete();
|
||||
|
||||
verifyCompilerOptions();
|
||||
if (!skipVerifyCompilerOptions) {
|
||||
verifyCompilerOptions();
|
||||
}
|
||||
performance.mark("afterProgram");
|
||||
performance.measure("Program", "beforeProgram", "afterProgram");
|
||||
tracing?.pop();
|
||||
|
||||
return program;
|
||||
|
||||
function updateAndGetProgramDiagnostics() {
|
||||
if (lazyProgramDiagnosticExplainingFile) {
|
||||
// Add file processingDiagnostics
|
||||
fileProcessingDiagnostics?.forEach(diagnostic => {
|
||||
switch (diagnostic.kind) {
|
||||
case FilePreprocessingDiagnosticsKind.FilePreprocessingFileExplainingDiagnostic:
|
||||
return programDiagnostics.add(
|
||||
createDiagnosticExplainingFile(
|
||||
diagnostic.file && getSourceFileByPath(diagnostic.file),
|
||||
diagnostic.fileProcessingReason,
|
||||
diagnostic.diagnostic,
|
||||
diagnostic.args || emptyArray,
|
||||
),
|
||||
);
|
||||
case FilePreprocessingDiagnosticsKind.FilePreprocessingLibReferenceDiagnostic:
|
||||
return programDiagnostics.add(filePreprocessingLibreferenceDiagnostic(diagnostic));
|
||||
case FilePreprocessingDiagnosticsKind.ResolutionDiagnostics:
|
||||
return diagnostic.diagnostics.forEach(d => programDiagnostics.add(d));
|
||||
default:
|
||||
Debug.assertNever(diagnostic);
|
||||
}
|
||||
});
|
||||
lazyProgramDiagnosticExplainingFile.forEach(({ file, diagnostic, args }) =>
|
||||
programDiagnostics.add(
|
||||
createDiagnosticExplainingFile(file, /*fileProcessingReason*/ undefined, diagnostic, args),
|
||||
)
|
||||
);
|
||||
lazyProgramDiagnosticExplainingFile = undefined;
|
||||
fileReasonsToChain = undefined;
|
||||
reasonToRelatedInfo = undefined;
|
||||
}
|
||||
return programDiagnostics;
|
||||
}
|
||||
|
||||
function filePreprocessingLibreferenceDiagnostic({ reason }: FilePreprocessingLibReferenceDiagnostic) {
|
||||
const { file, pos, end } = getReferencedFileLocation(program, reason) as ReferenceFileLocation;
|
||||
const libReference = file.libReferenceDirectives[reason.index];
|
||||
const libName = getLibNameFromLibReference(libReference);
|
||||
const unqualifiedLibName = removeSuffix(removePrefix(libName, "lib."), ".d.ts");
|
||||
const suggestion = getSpellingSuggestion(unqualifiedLibName, libs, identity);
|
||||
return createFileDiagnostic(
|
||||
file,
|
||||
Debug.checkDefined(pos),
|
||||
Debug.checkDefined(end) - pos,
|
||||
suggestion ? Diagnostics.Cannot_find_lib_definition_for_0_Did_you_mean_1 : Diagnostics.Cannot_find_lib_definition_for_0,
|
||||
libName,
|
||||
suggestion!,
|
||||
);
|
||||
}
|
||||
|
||||
function getResolvedModule(file: SourceFile, moduleName: string, mode: ResolutionMode) {
|
||||
return resolvedModules?.get(file.path)?.get(moduleName, mode);
|
||||
}
|
||||
@ -2170,7 +2032,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
|
||||
|
||||
function addResolutionDiagnostics(resolution: ResolvedModuleWithFailedLookupLocations | ResolvedTypeReferenceDirectiveWithFailedLookupLocations) {
|
||||
if (!resolution.resolutionDiagnostics?.length) return;
|
||||
(fileProcessingDiagnostics ??= []).push({
|
||||
programDiagnostics.addFileProcessingDiagnostic({
|
||||
kind: FilePreprocessingDiagnosticsKind.ResolutionDiagnostics,
|
||||
diagnostics: resolution.resolutionDiagnostics,
|
||||
});
|
||||
@ -2289,16 +2151,19 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
|
||||
}
|
||||
|
||||
function getCommonSourceDirectory() {
|
||||
if (commonSourceDirectory === undefined) {
|
||||
const emittedFiles = filter(files, file => sourceFileMayBeEmitted(file, program));
|
||||
commonSourceDirectory = ts_getCommonSourceDirectory(
|
||||
options,
|
||||
() => mapDefined(emittedFiles, file => file.isDeclarationFile ? undefined : file.fileName),
|
||||
currentDirectory,
|
||||
getCanonicalFileName,
|
||||
commonSourceDirectory => checkSourceFilesBelongToPath(emittedFiles, commonSourceDirectory),
|
||||
);
|
||||
let commonSourceDirectory = programDiagnostics.getCommonSourceDirectory();
|
||||
if (commonSourceDirectory !== undefined) {
|
||||
return commonSourceDirectory;
|
||||
}
|
||||
const emittedFiles = filter(files, file => sourceFileMayBeEmitted(file, program));
|
||||
commonSourceDirectory = ts_getCommonSourceDirectory(
|
||||
options,
|
||||
() => mapDefined(emittedFiles, file => file.isDeclarationFile ? undefined : file.fileName),
|
||||
currentDirectory,
|
||||
getCanonicalFileName,
|
||||
commonSourceDirectory => checkSourceFilesBelongToPath(emittedFiles, commonSourceDirectory),
|
||||
);
|
||||
programDiagnostics.setCommonSourceDirectory(commonSourceDirectory);
|
||||
return commonSourceDirectory;
|
||||
}
|
||||
|
||||
@ -2722,9 +2587,12 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
|
||||
filesByName.set(path, filesByName.get(oldFile.path));
|
||||
});
|
||||
|
||||
const isConfigIdentical = oldOptions.configFile && oldOptions.configFile === options.configFile
|
||||
|| !oldOptions.configFile && !options.configFile && !optionsHaveChanges(oldOptions, options, optionDeclarations);
|
||||
programDiagnostics.reuseStateFromOldProgram(oldProgram.getProgramDiagnosticsContainer(), isConfigIdentical);
|
||||
skipVerifyCompilerOptions = isConfigIdentical;
|
||||
|
||||
files = newSourceFiles;
|
||||
fileReasons = oldProgram.getFileIncludeReasons();
|
||||
fileProcessingDiagnostics = oldProgram.getFileProcessingDiagnostics();
|
||||
automaticTypeDirectiveNames = oldProgram.getAutomaticTypeDirectiveNames();
|
||||
automaticTypeDirectiveResolutions = oldProgram.getAutomaticTypeDirectiveResolutions();
|
||||
|
||||
@ -2985,7 +2853,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
|
||||
return emptyArray;
|
||||
}
|
||||
|
||||
const programDiagnosticsInFile = updateAndGetProgramDiagnostics().getDiagnostics(sourceFile.fileName);
|
||||
const programDiagnosticsInFile = programDiagnostics.getCombinedDiagnostics(program).getDiagnostics(sourceFile.fileName);
|
||||
if (!sourceFile.commentDirectives?.length) {
|
||||
return programDiagnosticsInFile;
|
||||
}
|
||||
@ -3435,16 +3303,16 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
|
||||
|
||||
function getOptionsDiagnostics(): SortedReadonlyArray<Diagnostic> {
|
||||
return sortAndDeduplicateDiagnostics(concatenate(
|
||||
updateAndGetProgramDiagnostics().getGlobalDiagnostics(),
|
||||
programDiagnostics.getCombinedDiagnostics(program).getGlobalDiagnostics(),
|
||||
getOptionsDiagnosticsOfConfigFile(),
|
||||
));
|
||||
}
|
||||
|
||||
function getOptionsDiagnosticsOfConfigFile() {
|
||||
if (!options.configFile) return emptyArray;
|
||||
let diagnostics = updateAndGetProgramDiagnostics().getDiagnostics(options.configFile.fileName);
|
||||
let diagnostics = programDiagnostics.getCombinedDiagnostics(program).getDiagnostics(options.configFile.fileName);
|
||||
forEachResolvedProjectReference(resolvedRef => {
|
||||
diagnostics = concatenate(diagnostics, updateAndGetProgramDiagnostics().getDiagnostics(resolvedRef.sourceFile.fileName));
|
||||
diagnostics = concatenate(diagnostics, programDiagnostics.getCombinedDiagnostics(program).getDiagnostics(resolvedRef.sourceFile.fileName));
|
||||
});
|
||||
return diagnostics;
|
||||
}
|
||||
@ -3666,7 +3534,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
|
||||
}
|
||||
|
||||
function reportFileNamesDifferOnlyInCasingError(fileName: string, existingFile: SourceFile, reason: FileIncludeReason): void {
|
||||
const hasExistingReasonToReportErrorOn = !isReferencedFile(reason) && some(fileReasons.get(existingFile.path), isReferencedFile);
|
||||
const hasExistingReasonToReportErrorOn = !isReferencedFile(reason) && some(programDiagnostics.getFileReasons().get(existingFile.path), isReferencedFile);
|
||||
if (hasExistingReasonToReportErrorOn) {
|
||||
addFilePreprocessingFileExplainingDiagnostic(existingFile, reason, Diagnostics.Already_included_file_name_0_differs_from_file_name_1_only_in_casing, [existingFile.fileName, fileName]);
|
||||
}
|
||||
@ -3881,7 +3749,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
|
||||
|
||||
function addFileIncludeReason(file: SourceFile | undefined, reason: FileIncludeReason, checkExisting: boolean) {
|
||||
if (file && (!checkExisting || !isReferencedFile(reason) || !filesWithReferencesProcessed?.has(reason.file))) {
|
||||
fileReasons.add(file.path, reason);
|
||||
programDiagnostics.getFileReasons().add(file.path, reason);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@ -4115,7 +3983,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
|
||||
processRootFile(pathForLibFile(libFileName), /*isDefaultLib*/ true, /*ignoreNoDefaultLib*/ true, { kind: FileIncludeKind.LibReferenceDirective, file: file.path, index });
|
||||
}
|
||||
else {
|
||||
(fileProcessingDiagnostics ||= []).push({
|
||||
programDiagnostics.addFileProcessingDiagnostic({
|
||||
kind: FilePreprocessingDiagnosticsKind.FilePreprocessingLibReferenceDiagnostic,
|
||||
reason: { kind: FileIncludeKind.LibReferenceDirective, file: file.path, index },
|
||||
});
|
||||
@ -4202,10 +4070,11 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
|
||||
if (!sourceFile.isDeclarationFile) {
|
||||
const absoluteSourceFilePath = host.getCanonicalFileName(getNormalizedAbsolutePath(sourceFile.fileName, currentDirectory));
|
||||
if (absoluteSourceFilePath.indexOf(absoluteRootDirectoryPath) !== 0) {
|
||||
addLazyProgramDiagnosticExplainingFile(
|
||||
programDiagnostics.addLazyConfigDiagnostic(
|
||||
sourceFile,
|
||||
Diagnostics.File_0_is_not_under_rootDir_1_rootDir_is_expected_to_contain_all_source_files,
|
||||
[sourceFile.fileName, rootDirectory],
|
||||
sourceFile.fileName,
|
||||
rootDirectory,
|
||||
);
|
||||
allFilesBelongToPath = false;
|
||||
}
|
||||
@ -4308,7 +4177,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
|
||||
|
||||
const outputFile = options.outFile;
|
||||
if (!options.tsBuildInfoFile && options.incremental && !outputFile && !options.configFilePath) {
|
||||
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Option_incremental_can_only_be_specified_using_tsconfig_emitting_to_single_file_or_when_option_tsBuildInfoFile_is_specified));
|
||||
programDiagnostics.addConfigDiagnostic(createCompilerDiagnostic(Diagnostics.Option_incremental_can_only_be_specified_using_tsconfig_emitting_to_single_file_or_when_option_tsBuildInfoFile_is_specified));
|
||||
}
|
||||
|
||||
verifyDeprecatedCompilerOptions();
|
||||
@ -4320,10 +4189,11 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
|
||||
for (const file of files) {
|
||||
// Ignore file that is not emitted
|
||||
if (sourceFileMayBeEmitted(file, program) && !rootPaths.has(file.path)) {
|
||||
addLazyProgramDiagnosticExplainingFile(
|
||||
programDiagnostics.addLazyConfigDiagnostic(
|
||||
file,
|
||||
Diagnostics.File_0_is_not_listed_within_the_file_list_of_project_1_Projects_must_list_all_files_or_use_an_include_pattern,
|
||||
[file.fileName, options.configFilePath || ""],
|
||||
file.fileName,
|
||||
options.configFilePath || "",
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -4410,7 +4280,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
|
||||
else if (firstNonAmbientExternalModuleSourceFile && languageVersion < ScriptTarget.ES2015 && options.module === ModuleKind.None) {
|
||||
// We cannot use createDiagnosticFromNode because nodes do not have parents yet
|
||||
const span = getErrorSpanForNode(firstNonAmbientExternalModuleSourceFile, typeof firstNonAmbientExternalModuleSourceFile.externalModuleIndicator === "boolean" ? firstNonAmbientExternalModuleSourceFile : firstNonAmbientExternalModuleSourceFile.externalModuleIndicator!);
|
||||
programDiagnostics.add(createFileDiagnostic(firstNonAmbientExternalModuleSourceFile, span.start, span.length, Diagnostics.Cannot_use_imports_exports_or_module_augmentations_when_module_is_none));
|
||||
programDiagnostics.addConfigDiagnostic(createFileDiagnostic(firstNonAmbientExternalModuleSourceFile, span.start, span.length, Diagnostics.Cannot_use_imports_exports_or_module_augmentations_when_module_is_none));
|
||||
}
|
||||
|
||||
// Cannot specify module gen that isn't amd or system with --out
|
||||
@ -4420,7 +4290,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
|
||||
}
|
||||
else if (options.module === undefined && firstNonAmbientExternalModuleSourceFile) {
|
||||
const span = getErrorSpanForNode(firstNonAmbientExternalModuleSourceFile, typeof firstNonAmbientExternalModuleSourceFile.externalModuleIndicator === "boolean" ? firstNonAmbientExternalModuleSourceFile : firstNonAmbientExternalModuleSourceFile.externalModuleIndicator!);
|
||||
programDiagnostics.add(createFileDiagnostic(firstNonAmbientExternalModuleSourceFile, span.start, span.length, Diagnostics.Cannot_compile_modules_using_option_0_unless_the_module_flag_is_amd_or_system, "outFile"));
|
||||
programDiagnostics.addConfigDiagnostic(createFileDiagnostic(firstNonAmbientExternalModuleSourceFile, span.start, span.length, Diagnostics.Cannot_compile_modules_using_option_0_unless_the_module_flag_is_amd_or_system, "outFile"));
|
||||
}
|
||||
}
|
||||
|
||||
@ -4699,123 +4569,8 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
|
||||
});
|
||||
}
|
||||
|
||||
function createDiagnosticExplainingFile(file: SourceFile | undefined, fileProcessingReason: FileIncludeReason | undefined, diagnostic: DiagnosticMessage, args: DiagnosticArguments): Diagnostic {
|
||||
let seenReasons: Set<FileIncludeReason> | undefined;
|
||||
const reasons = file && fileReasons.get(file.path);
|
||||
let fileIncludeReasons: DiagnosticMessageChain[] | undefined;
|
||||
let relatedInfo: DiagnosticWithLocation[] | undefined;
|
||||
let locationReason = isReferencedFile(fileProcessingReason) ? fileProcessingReason : undefined;
|
||||
let fileIncludeReasonDetails: DiagnosticMessageChain | undefined;
|
||||
let redirectInfo: DiagnosticMessageChain[] | undefined;
|
||||
let cachedChain = file && fileReasonsToChain?.get(file.path);
|
||||
let chain: DiagnosticMessageChain | undefined;
|
||||
if (cachedChain) {
|
||||
if (cachedChain.fileIncludeReasonDetails) {
|
||||
seenReasons = new Set(reasons);
|
||||
reasons?.forEach(populateRelatedInfo);
|
||||
}
|
||||
else {
|
||||
reasons?.forEach(processReason);
|
||||
}
|
||||
redirectInfo = cachedChain.redirectInfo;
|
||||
}
|
||||
else {
|
||||
reasons?.forEach(processReason);
|
||||
redirectInfo = file && explainIfFileIsRedirectAndImpliedFormat(file, getCompilerOptionsForFile(file));
|
||||
}
|
||||
|
||||
if (fileProcessingReason) processReason(fileProcessingReason);
|
||||
const processedExtraReason = seenReasons?.size !== reasons?.length;
|
||||
|
||||
// If we have location and there is only one reason file is in which is the location, dont add details for file include
|
||||
if (locationReason && seenReasons?.size === 1) seenReasons = undefined;
|
||||
|
||||
if (seenReasons && cachedChain) {
|
||||
if (cachedChain.details && !processedExtraReason) {
|
||||
chain = chainDiagnosticMessages(cachedChain.details, diagnostic, ...args || emptyArray);
|
||||
}
|
||||
else if (cachedChain.fileIncludeReasonDetails) {
|
||||
if (!processedExtraReason) {
|
||||
if (!cachedFileIncludeDetailsHasProcessedExtraReason()) {
|
||||
fileIncludeReasonDetails = cachedChain.fileIncludeReasonDetails;
|
||||
}
|
||||
else {
|
||||
fileIncludeReasons = cachedChain.fileIncludeReasonDetails.next!.slice(0, reasons!.length);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!cachedFileIncludeDetailsHasProcessedExtraReason()) {
|
||||
fileIncludeReasons = [...cachedChain.fileIncludeReasonDetails.next!, fileIncludeReasons![0]];
|
||||
}
|
||||
else {
|
||||
fileIncludeReasons = append(cachedChain.fileIncludeReasonDetails.next!.slice(0, reasons!.length), fileIncludeReasons![0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!chain) {
|
||||
if (!fileIncludeReasonDetails) fileIncludeReasonDetails = seenReasons && chainDiagnosticMessages(fileIncludeReasons, Diagnostics.The_file_is_in_the_program_because_Colon);
|
||||
chain = chainDiagnosticMessages(
|
||||
redirectInfo ?
|
||||
fileIncludeReasonDetails ? [fileIncludeReasonDetails, ...redirectInfo] : redirectInfo :
|
||||
fileIncludeReasonDetails,
|
||||
diagnostic,
|
||||
...args || emptyArray,
|
||||
);
|
||||
}
|
||||
|
||||
// This is chain's next contains:
|
||||
// - File is in program because:
|
||||
// - Files reasons listed
|
||||
// - extra reason if its not already processed - this happens in case sensitive file system where files differ in casing and we are giving reasons for two files so reason is not in file's reason
|
||||
// fyi above whole secton is ommited if we have single reason and we are reporting at that reason's location
|
||||
// - redirect and additional information about file
|
||||
// So cache result if we havent ommited file include reasons
|
||||
if (file) {
|
||||
if (cachedChain) {
|
||||
// Cache new fileIncludeDetails if we have update
|
||||
// Or if we had cached with more details than the reasons
|
||||
if (!cachedChain.fileIncludeReasonDetails || (!processedExtraReason && fileIncludeReasonDetails)) {
|
||||
cachedChain.fileIncludeReasonDetails = fileIncludeReasonDetails;
|
||||
}
|
||||
}
|
||||
else {
|
||||
(fileReasonsToChain ??= new Map()).set(file.path, cachedChain = { fileIncludeReasonDetails, redirectInfo });
|
||||
}
|
||||
// If we didnt compute extra file include reason , cache the details to use directly
|
||||
if (!cachedChain.details && !processedExtraReason) cachedChain.details = chain.next;
|
||||
}
|
||||
|
||||
const location = locationReason && getReferencedFileLocation(program, locationReason);
|
||||
return location && isReferenceFileLocation(location) ?
|
||||
createFileDiagnosticFromMessageChain(location.file, location.pos, location.end - location.pos, chain, relatedInfo) :
|
||||
createCompilerDiagnosticFromMessageChain(chain, relatedInfo);
|
||||
|
||||
function processReason(reason: FileIncludeReason) {
|
||||
if (seenReasons?.has(reason)) return;
|
||||
(seenReasons ??= new Set()).add(reason);
|
||||
(fileIncludeReasons ??= []).push(fileIncludeReasonToDiagnostics(program, reason));
|
||||
populateRelatedInfo(reason);
|
||||
}
|
||||
|
||||
function populateRelatedInfo(reason: FileIncludeReason) {
|
||||
if (!locationReason && isReferencedFile(reason)) {
|
||||
// Report error at first reference file or file currently in processing and dont report in related information
|
||||
locationReason = reason;
|
||||
}
|
||||
else if (locationReason !== reason) {
|
||||
relatedInfo = append(relatedInfo, getFileIncludeReasonToRelatedInformation(reason));
|
||||
}
|
||||
}
|
||||
|
||||
function cachedFileIncludeDetailsHasProcessedExtraReason() {
|
||||
return cachedChain!.fileIncludeReasonDetails!.next?.length !== reasons?.length;
|
||||
}
|
||||
}
|
||||
|
||||
function addFilePreprocessingFileExplainingDiagnostic(file: SourceFile | undefined, fileProcessingReason: FileIncludeReason, diagnostic: DiagnosticMessage, args: DiagnosticArguments) {
|
||||
(fileProcessingDiagnostics ||= []).push({
|
||||
programDiagnostics.addFileProcessingDiagnostic({
|
||||
kind: FilePreprocessingDiagnosticsKind.FilePreprocessingFileExplainingDiagnostic,
|
||||
file: file && file.path,
|
||||
fileProcessingReason,
|
||||
@ -4824,111 +4579,6 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
|
||||
});
|
||||
}
|
||||
|
||||
function addLazyProgramDiagnosticExplainingFile(file: SourceFile, diagnostic: DiagnosticMessage, args: DiagnosticArguments) {
|
||||
lazyProgramDiagnosticExplainingFile!.push({ file, diagnostic, args });
|
||||
}
|
||||
|
||||
function getFileIncludeReasonToRelatedInformation(reason: FileIncludeReason) {
|
||||
let relatedInfo = reasonToRelatedInfo?.get(reason);
|
||||
if (relatedInfo === undefined) (reasonToRelatedInfo ??= new Map()).set(reason, relatedInfo = fileIncludeReasonToRelatedInformation(reason) ?? false);
|
||||
return relatedInfo || undefined;
|
||||
}
|
||||
|
||||
function fileIncludeReasonToRelatedInformation(reason: FileIncludeReason): DiagnosticWithLocation | undefined {
|
||||
if (isReferencedFile(reason)) {
|
||||
const referenceLocation = getReferencedFileLocation(program, reason);
|
||||
let message: DiagnosticMessage;
|
||||
switch (reason.kind) {
|
||||
case FileIncludeKind.Import:
|
||||
message = Diagnostics.File_is_included_via_import_here;
|
||||
break;
|
||||
case FileIncludeKind.ReferenceFile:
|
||||
message = Diagnostics.File_is_included_via_reference_here;
|
||||
break;
|
||||
case FileIncludeKind.TypeReferenceDirective:
|
||||
message = Diagnostics.File_is_included_via_type_library_reference_here;
|
||||
break;
|
||||
case FileIncludeKind.LibReferenceDirective:
|
||||
message = Diagnostics.File_is_included_via_library_reference_here;
|
||||
break;
|
||||
default:
|
||||
Debug.assertNever(reason);
|
||||
}
|
||||
return isReferenceFileLocation(referenceLocation) ? createFileDiagnostic(
|
||||
referenceLocation.file,
|
||||
referenceLocation.pos,
|
||||
referenceLocation.end - referenceLocation.pos,
|
||||
message,
|
||||
) : undefined;
|
||||
}
|
||||
|
||||
if (!options.configFile) return undefined;
|
||||
let configFileNode: Node | undefined;
|
||||
let message: DiagnosticMessage;
|
||||
switch (reason.kind) {
|
||||
case FileIncludeKind.RootFile:
|
||||
if (!options.configFile.configFileSpecs) return undefined;
|
||||
const fileName = getNormalizedAbsolutePath(rootNames[reason.index], currentDirectory);
|
||||
const matchedByFiles = getMatchedFileSpec(program, fileName);
|
||||
if (matchedByFiles) {
|
||||
configFileNode = getTsConfigPropArrayElementValue(options.configFile, "files", matchedByFiles);
|
||||
message = Diagnostics.File_is_matched_by_files_list_specified_here;
|
||||
break;
|
||||
}
|
||||
const matchedByInclude = getMatchedIncludeSpec(program, fileName);
|
||||
// Could be additional files specified as roots
|
||||
if (!matchedByInclude || !isString(matchedByInclude)) return undefined;
|
||||
configFileNode = getTsConfigPropArrayElementValue(options.configFile, "include", matchedByInclude);
|
||||
message = Diagnostics.File_is_matched_by_include_pattern_specified_here;
|
||||
break;
|
||||
case FileIncludeKind.SourceFromProjectReference:
|
||||
case FileIncludeKind.OutputFromProjectReference:
|
||||
const referencedResolvedRef = Debug.checkDefined(resolvedProjectReferences?.[reason.index]);
|
||||
const referenceInfo = forEachProjectReference(
|
||||
projectReferences,
|
||||
resolvedProjectReferences,
|
||||
(resolvedRef, parent, index) =>
|
||||
resolvedRef === referencedResolvedRef ?
|
||||
{ sourceFile: parent?.sourceFile || options.configFile!, index } :
|
||||
undefined,
|
||||
);
|
||||
if (!referenceInfo) return undefined;
|
||||
const { sourceFile, index } = referenceInfo;
|
||||
const referencesSyntax = forEachTsConfigPropArray(sourceFile as TsConfigSourceFile, "references", property => isArrayLiteralExpression(property.initializer) ? property.initializer : undefined);
|
||||
return referencesSyntax && referencesSyntax.elements.length > index ?
|
||||
createDiagnosticForNodeInSourceFile(
|
||||
sourceFile,
|
||||
referencesSyntax.elements[index],
|
||||
reason.kind === FileIncludeKind.OutputFromProjectReference ?
|
||||
Diagnostics.File_is_output_from_referenced_project_specified_here :
|
||||
Diagnostics.File_is_source_from_referenced_project_specified_here,
|
||||
) :
|
||||
undefined;
|
||||
case FileIncludeKind.AutomaticTypeDirectiveFile:
|
||||
if (!options.types) return undefined;
|
||||
configFileNode = getOptionsSyntaxByArrayElementValue("types", reason.typeReference);
|
||||
message = Diagnostics.File_is_entry_point_of_type_library_specified_here;
|
||||
break;
|
||||
case FileIncludeKind.LibFile:
|
||||
if (reason.index !== undefined) {
|
||||
configFileNode = getOptionsSyntaxByArrayElementValue("lib", options.lib![reason.index]);
|
||||
message = Diagnostics.File_is_library_specified_here;
|
||||
break;
|
||||
}
|
||||
const target = getNameOfScriptTarget(getEmitScriptTarget(options));
|
||||
configFileNode = target ? getOptionsSyntaxByValue("target", target) : undefined;
|
||||
message = Diagnostics.File_is_default_library_for_target_specified_here;
|
||||
break;
|
||||
default:
|
||||
Debug.assertNever(reason);
|
||||
}
|
||||
return configFileNode && createDiagnosticForNodeInSourceFile(
|
||||
options.configFile,
|
||||
configFileNode,
|
||||
message,
|
||||
);
|
||||
}
|
||||
|
||||
function verifyProjectReferences() {
|
||||
const buildInfoPath = !options.suppressOutputPathCheck ? getTsBuildInfoEmitOutputFilePath(options) : undefined;
|
||||
forEachProjectReference(
|
||||
@ -4966,7 +4616,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
|
||||
forEachPropertyAssignment(pathProp.initializer, key, keyProps => {
|
||||
const initializer = keyProps.initializer;
|
||||
if (isArrayLiteralExpression(initializer) && initializer.elements.length > valueIndex) {
|
||||
programDiagnostics.add(createDiagnosticForNodeInSourceFile(options.configFile!, initializer.elements[valueIndex], message, ...args));
|
||||
programDiagnostics.addConfigDiagnostic(createDiagnosticForNodeInSourceFile(options.configFile!, initializer.elements[valueIndex], message, ...args));
|
||||
needCompilerDiagnostic = false;
|
||||
}
|
||||
});
|
||||
@ -4999,21 +4649,8 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
|
||||
}
|
||||
}
|
||||
|
||||
function forEachOptionsSyntaxByName<T>(name: string, callback: (prop: PropertyAssignment) => T | undefined): T | undefined {
|
||||
return forEachPropertyAssignment(getCompilerOptionsObjectLiteralSyntax(), name, callback);
|
||||
}
|
||||
|
||||
function forEachOptionPathsSyntax<T>(callback: (prop: PropertyAssignment) => T | undefined) {
|
||||
return forEachOptionsSyntaxByName("paths", callback);
|
||||
}
|
||||
|
||||
function getOptionsSyntaxByValue(name: string, value: string) {
|
||||
return forEachOptionsSyntaxByName(name, property => isStringLiteral(property.initializer) && property.initializer.text === value ? property.initializer : undefined);
|
||||
}
|
||||
|
||||
function getOptionsSyntaxByArrayElementValue(name: string, value: string) {
|
||||
const compilerOptionsObjectLiteralSyntax = getCompilerOptionsObjectLiteralSyntax();
|
||||
return compilerOptionsObjectLiteralSyntax && getPropertyArrayElementValue(compilerOptionsObjectLiteralSyntax, name, value);
|
||||
return forEachOptionsSyntaxByName(getCompilerOptionsObjectLiteralSyntax(), "paths", callback);
|
||||
}
|
||||
|
||||
function createDiagnosticForOptionName(message: DiagnosticMessage, option1: string, option2?: string, option3?: string) {
|
||||
@ -5028,10 +4665,10 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
|
||||
function createDiagnosticForReference(sourceFile: JsonSourceFile | undefined, index: number, message: DiagnosticMessage, ...args: DiagnosticArguments) {
|
||||
const referencesSyntax = forEachTsConfigPropArray(sourceFile || options.configFile, "references", property => isArrayLiteralExpression(property.initializer) ? property.initializer : undefined);
|
||||
if (referencesSyntax && referencesSyntax.elements.length > index) {
|
||||
programDiagnostics.add(createDiagnosticForNodeInSourceFile(sourceFile || options.configFile!, referencesSyntax.elements[index], message, ...args));
|
||||
programDiagnostics.addConfigDiagnostic(createDiagnosticForNodeInSourceFile(sourceFile || options.configFile!, referencesSyntax.elements[index], message, ...args));
|
||||
}
|
||||
else {
|
||||
programDiagnostics.add(createCompilerDiagnostic(message, ...args));
|
||||
programDiagnostics.addConfigDiagnostic(createCompilerDiagnostic(message, ...args));
|
||||
}
|
||||
}
|
||||
|
||||
@ -5055,18 +4692,18 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
|
||||
if (compilerOptionsProperty) {
|
||||
// eslint-disable-next-line local/no-in-operator
|
||||
if ("messageText" in message) {
|
||||
programDiagnostics.add(createDiagnosticForNodeFromMessageChain(options.configFile!, compilerOptionsProperty.name, message));
|
||||
programDiagnostics.addConfigDiagnostic(createDiagnosticForNodeFromMessageChain(options.configFile!, compilerOptionsProperty.name, message));
|
||||
}
|
||||
else {
|
||||
programDiagnostics.add(createDiagnosticForNodeInSourceFile(options.configFile!, compilerOptionsProperty.name, message, ...args));
|
||||
programDiagnostics.addConfigDiagnostic(createDiagnosticForNodeInSourceFile(options.configFile!, compilerOptionsProperty.name, message, ...args));
|
||||
}
|
||||
}
|
||||
// eslint-disable-next-line local/no-in-operator
|
||||
else if ("messageText" in message) {
|
||||
programDiagnostics.add(createCompilerDiagnosticFromMessageChain(message));
|
||||
programDiagnostics.addConfigDiagnostic(createCompilerDiagnosticFromMessageChain(message));
|
||||
}
|
||||
else {
|
||||
programDiagnostics.add(createCompilerDiagnostic(message, ...args));
|
||||
programDiagnostics.addConfigDiagnostic(createCompilerDiagnostic(message, ...args));
|
||||
}
|
||||
}
|
||||
|
||||
@ -5097,10 +4734,10 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
|
||||
forEachPropertyAssignment(objectLiteral, key1, prop => {
|
||||
// eslint-disable-next-line local/no-in-operator
|
||||
if ("messageText" in message) {
|
||||
programDiagnostics.add(createDiagnosticForNodeFromMessageChain(options.configFile!, onKey ? prop.name : prop.initializer, message));
|
||||
programDiagnostics.addConfigDiagnostic(createDiagnosticForNodeFromMessageChain(options.configFile!, onKey ? prop.name : prop.initializer, message));
|
||||
}
|
||||
else {
|
||||
programDiagnostics.add(createDiagnosticForNodeInSourceFile(options.configFile!, onKey ? prop.name : prop.initializer, message, ...args));
|
||||
programDiagnostics.addConfigDiagnostic(createDiagnosticForNodeInSourceFile(options.configFile!, onKey ? prop.name : prop.initializer, message, ...args));
|
||||
}
|
||||
needsCompilerDiagnostic = true;
|
||||
}, key2);
|
||||
@ -5109,7 +4746,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
|
||||
|
||||
function blockEmittingOfFile(emitFileName: string, diag: Diagnostic) {
|
||||
hasEmitBlockingDiagnostics.set(toPath(emitFileName), true);
|
||||
programDiagnostics.add(diag);
|
||||
programDiagnostics.addConfigDiagnostic(diag);
|
||||
}
|
||||
|
||||
function isEmittedFile(file: string): boolean {
|
||||
|
||||
426
src/compiler/programDiagnostics.ts
Normal file
426
src/compiler/programDiagnostics.ts
Normal file
@ -0,0 +1,426 @@
|
||||
import {
|
||||
append,
|
||||
chainDiagnosticMessages,
|
||||
createCompilerDiagnosticFromMessageChain,
|
||||
createDiagnosticCollection,
|
||||
createDiagnosticForNodeInSourceFile,
|
||||
createFileDiagnostic,
|
||||
createFileDiagnosticFromMessageChain,
|
||||
createMultiMap,
|
||||
Debug,
|
||||
Diagnostic,
|
||||
DiagnosticArguments,
|
||||
DiagnosticCollection,
|
||||
DiagnosticMessage,
|
||||
DiagnosticMessageChain,
|
||||
Diagnostics,
|
||||
DiagnosticWithLocation,
|
||||
emptyArray,
|
||||
explainIfFileIsRedirectAndImpliedFormat,
|
||||
FileIncludeKind,
|
||||
FileIncludeReason,
|
||||
fileIncludeReasonToDiagnostics,
|
||||
FilePreprocessingDiagnostics,
|
||||
FilePreprocessingDiagnosticsKind,
|
||||
FilePreprocessingLibReferenceDiagnostic,
|
||||
forEachProjectReference,
|
||||
forEachTsConfigPropArray,
|
||||
getEmitScriptTarget,
|
||||
getLibNameFromLibReference,
|
||||
getMatchedFileSpec,
|
||||
getMatchedIncludeSpec,
|
||||
getNameOfScriptTarget,
|
||||
getNormalizedAbsolutePath,
|
||||
getOptionsSyntaxByArrayElementValue,
|
||||
getOptionsSyntaxByValue,
|
||||
getReferencedFileLocation,
|
||||
getSpellingSuggestion,
|
||||
getTsConfigPropArrayElementValue,
|
||||
identity,
|
||||
isArrayLiteralExpression,
|
||||
isReferencedFile,
|
||||
isReferenceFileLocation,
|
||||
isString,
|
||||
libs,
|
||||
MultiMap,
|
||||
Node,
|
||||
ObjectLiteralExpression,
|
||||
Path,
|
||||
Program,
|
||||
ReferenceFileLocation,
|
||||
removePrefix,
|
||||
removeSuffix,
|
||||
SourceFile,
|
||||
TsConfigSourceFile,
|
||||
} from "./_namespaces/ts.js";
|
||||
|
||||
interface FileReasonToChainCache {
|
||||
fileIncludeReasonDetails: DiagnosticMessageChain | undefined;
|
||||
redirectInfo: DiagnosticMessageChain[] | undefined;
|
||||
details?: DiagnosticMessageChain[];
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export interface LazyConfigDiagnostic {
|
||||
file: SourceFile;
|
||||
diagnostic: DiagnosticMessage;
|
||||
args: DiagnosticArguments;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export interface ProgramDiagnostics {
|
||||
addConfigDiagnostic(diag: Diagnostic): void;
|
||||
addLazyConfigDiagnostic(file: SourceFile, message: DiagnosticMessage, ...args: DiagnosticArguments): void;
|
||||
addFileProcessingDiagnostic(diag: FilePreprocessingDiagnostics): void;
|
||||
setCommonSourceDirectory(directory: string): void;
|
||||
|
||||
reuseStateFromOldProgram(oldProgramDiagnostics: ProgramDiagnostics, isConfigIdentical: boolean): void;
|
||||
|
||||
getFileProcessingDiagnostics(): FilePreprocessingDiagnostics[] | undefined;
|
||||
getFileReasons(): MultiMap<Path, FileIncludeReason>;
|
||||
getConfigDiagnostics(): DiagnosticCollection | undefined;
|
||||
getLazyConfigDiagnostics(): LazyConfigDiagnostic[] | undefined;
|
||||
getCommonSourceDirectory(): string | undefined;
|
||||
getCombinedDiagnostics(program: Program): DiagnosticCollection;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function createProgramDiagnostics(getCompilerOptionsObjectLiteralSyntax: () => ObjectLiteralExpression | undefined): ProgramDiagnostics {
|
||||
// Only valid for a single program. The individual components can be reused under certain
|
||||
// circumstances (described below), but during `getCombinedDiagnostics`, position information
|
||||
// is applied to the diagnostics, so they cannot be shared between programs.
|
||||
let computedDiagnostics: DiagnosticCollection | undefined;
|
||||
|
||||
// Valid between programs if `StructureIsReused.Completely`.
|
||||
let fileReasons = createMultiMap<Path, FileIncludeReason>();
|
||||
let fileProcessingDiagnostics: FilePreprocessingDiagnostics[] | undefined;
|
||||
|
||||
// Valid between programs if `StructureIsReused.Completely` and config file is identical.
|
||||
let commonSourceDirectory: string | undefined;
|
||||
let configDiagnostics: DiagnosticCollection | undefined;
|
||||
let lazyConfigDiagnostics: LazyConfigDiagnostic[] | undefined;
|
||||
|
||||
// Local state, only used during getDiagnostics
|
||||
let fileReasonsToChain: Map<Path, FileReasonToChainCache> | undefined;
|
||||
let reasonToRelatedInfo: Map<FileIncludeReason, DiagnosticWithLocation | false> | undefined;
|
||||
|
||||
return {
|
||||
addConfigDiagnostic(diag) {
|
||||
Debug.assert(computedDiagnostics === undefined, "Cannot modify program diagnostic state after requesting combined diagnostics");
|
||||
(configDiagnostics ??= createDiagnosticCollection()).add(diag);
|
||||
},
|
||||
addLazyConfigDiagnostic(file, message, ...args) {
|
||||
Debug.assert(computedDiagnostics === undefined, "Cannot modify program diagnostic state after requesting combined diagnostics");
|
||||
(lazyConfigDiagnostics ??= []).push({ file, diagnostic: message, args });
|
||||
},
|
||||
addFileProcessingDiagnostic(diag) {
|
||||
Debug.assert(computedDiagnostics === undefined, "Cannot modify program diagnostic state after requesting combined diagnostics");
|
||||
(fileProcessingDiagnostics ??= []).push(diag);
|
||||
},
|
||||
setCommonSourceDirectory(directory) {
|
||||
commonSourceDirectory = directory;
|
||||
},
|
||||
|
||||
reuseStateFromOldProgram(oldProgramDiagnostics, isConfigIdentical) {
|
||||
fileReasons = oldProgramDiagnostics.getFileReasons();
|
||||
fileProcessingDiagnostics = oldProgramDiagnostics.getFileProcessingDiagnostics();
|
||||
if (isConfigIdentical) {
|
||||
commonSourceDirectory = oldProgramDiagnostics.getCommonSourceDirectory();
|
||||
configDiagnostics = oldProgramDiagnostics.getConfigDiagnostics();
|
||||
lazyConfigDiagnostics = oldProgramDiagnostics.getLazyConfigDiagnostics();
|
||||
}
|
||||
},
|
||||
|
||||
getFileProcessingDiagnostics() {
|
||||
return fileProcessingDiagnostics;
|
||||
},
|
||||
getFileReasons() {
|
||||
return fileReasons;
|
||||
},
|
||||
getCommonSourceDirectory() {
|
||||
return commonSourceDirectory;
|
||||
},
|
||||
getConfigDiagnostics() {
|
||||
return configDiagnostics;
|
||||
},
|
||||
getLazyConfigDiagnostics() {
|
||||
return lazyConfigDiagnostics;
|
||||
},
|
||||
getCombinedDiagnostics(program: Program) {
|
||||
if (computedDiagnostics) {
|
||||
return computedDiagnostics;
|
||||
}
|
||||
|
||||
computedDiagnostics = createDiagnosticCollection();
|
||||
|
||||
configDiagnostics?.getDiagnostics().forEach(d => computedDiagnostics!.add(d));
|
||||
|
||||
fileProcessingDiagnostics?.forEach(diagnostic => {
|
||||
switch (diagnostic.kind) {
|
||||
case FilePreprocessingDiagnosticsKind.FilePreprocessingFileExplainingDiagnostic:
|
||||
return computedDiagnostics!.add(
|
||||
createDiagnosticExplainingFile(
|
||||
program,
|
||||
diagnostic.file && program.getSourceFileByPath(diagnostic.file),
|
||||
diagnostic.fileProcessingReason,
|
||||
diagnostic.diagnostic,
|
||||
diagnostic.args || emptyArray,
|
||||
),
|
||||
);
|
||||
case FilePreprocessingDiagnosticsKind.FilePreprocessingLibReferenceDiagnostic:
|
||||
return computedDiagnostics!.add(filePreprocessingLibreferenceDiagnostic(program, diagnostic));
|
||||
case FilePreprocessingDiagnosticsKind.ResolutionDiagnostics:
|
||||
return diagnostic.diagnostics.forEach(d => computedDiagnostics!.add(d));
|
||||
default:
|
||||
Debug.assertNever(diagnostic);
|
||||
}
|
||||
});
|
||||
lazyConfigDiagnostics?.forEach(({ file, diagnostic, args }) =>
|
||||
computedDiagnostics!.add(
|
||||
createDiagnosticExplainingFile(program, file, /*fileProcessingReason*/ undefined, diagnostic, args),
|
||||
)
|
||||
);
|
||||
fileReasonsToChain = undefined;
|
||||
reasonToRelatedInfo = undefined;
|
||||
return computedDiagnostics;
|
||||
},
|
||||
};
|
||||
|
||||
function filePreprocessingLibreferenceDiagnostic(program: Program, { reason }: FilePreprocessingLibReferenceDiagnostic) {
|
||||
const { file, pos, end } = getReferencedFileLocation(program, reason) as ReferenceFileLocation;
|
||||
const libReference = file.libReferenceDirectives[reason.index];
|
||||
const libName = getLibNameFromLibReference(libReference);
|
||||
const unqualifiedLibName = removeSuffix(removePrefix(libName, "lib."), ".d.ts");
|
||||
const suggestion = getSpellingSuggestion(unqualifiedLibName, libs, identity);
|
||||
return createFileDiagnostic(
|
||||
file,
|
||||
Debug.checkDefined(pos),
|
||||
Debug.checkDefined(end) - pos,
|
||||
suggestion ? Diagnostics.Cannot_find_lib_definition_for_0_Did_you_mean_1 : Diagnostics.Cannot_find_lib_definition_for_0,
|
||||
libName,
|
||||
suggestion!,
|
||||
);
|
||||
}
|
||||
|
||||
function createDiagnosticExplainingFile(program: Program, file: SourceFile | undefined, fileProcessingReason: FileIncludeReason | undefined, diagnostic: DiagnosticMessage, args: DiagnosticArguments): Diagnostic {
|
||||
let seenReasons: Set<FileIncludeReason> | undefined;
|
||||
let fileIncludeReasons: DiagnosticMessageChain[] | undefined;
|
||||
let relatedInfo: DiagnosticWithLocation[] | undefined;
|
||||
let fileIncludeReasonDetails: DiagnosticMessageChain | undefined;
|
||||
let redirectInfo: DiagnosticMessageChain[] | undefined;
|
||||
let chain: DiagnosticMessageChain | undefined;
|
||||
|
||||
const reasons = file && fileReasons.get(file.path);
|
||||
let locationReason = isReferencedFile(fileProcessingReason) ? fileProcessingReason : undefined;
|
||||
let cachedChain = file && fileReasonsToChain?.get(file.path);
|
||||
if (cachedChain) {
|
||||
if (cachedChain.fileIncludeReasonDetails) {
|
||||
seenReasons = new Set(reasons);
|
||||
reasons?.forEach(populateRelatedInfo);
|
||||
}
|
||||
else {
|
||||
reasons?.forEach(processReason);
|
||||
}
|
||||
redirectInfo = cachedChain.redirectInfo;
|
||||
}
|
||||
else {
|
||||
reasons?.forEach(processReason);
|
||||
redirectInfo = file && explainIfFileIsRedirectAndImpliedFormat(file, program.getCompilerOptionsForFile(file));
|
||||
}
|
||||
|
||||
if (fileProcessingReason) processReason(fileProcessingReason);
|
||||
const processedExtraReason = seenReasons?.size !== reasons?.length;
|
||||
|
||||
// If we have location and there is only one reason file is in which is the location, dont add details for file include
|
||||
if (locationReason && seenReasons?.size === 1) seenReasons = undefined;
|
||||
|
||||
if (seenReasons && cachedChain) {
|
||||
if (cachedChain.details && !processedExtraReason) {
|
||||
chain = chainDiagnosticMessages(cachedChain.details, diagnostic, ...args ?? emptyArray);
|
||||
}
|
||||
else if (cachedChain.fileIncludeReasonDetails) {
|
||||
if (!processedExtraReason) {
|
||||
if (!cachedFileIncludeDetailsHasProcessedExtraReason()) {
|
||||
fileIncludeReasonDetails = cachedChain.fileIncludeReasonDetails;
|
||||
}
|
||||
else {
|
||||
fileIncludeReasons = cachedChain.fileIncludeReasonDetails.next!.slice(0, reasons!.length);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!cachedFileIncludeDetailsHasProcessedExtraReason()) {
|
||||
fileIncludeReasons = [...cachedChain.fileIncludeReasonDetails.next!, fileIncludeReasons![0]];
|
||||
}
|
||||
else {
|
||||
fileIncludeReasons = append(cachedChain.fileIncludeReasonDetails.next!.slice(0, reasons!.length), fileIncludeReasons![0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!chain) {
|
||||
if (!fileIncludeReasonDetails) fileIncludeReasonDetails = seenReasons && chainDiagnosticMessages(fileIncludeReasons, Diagnostics.The_file_is_in_the_program_because_Colon);
|
||||
chain = chainDiagnosticMessages(
|
||||
redirectInfo ?
|
||||
fileIncludeReasonDetails ? [fileIncludeReasonDetails, ...redirectInfo] : redirectInfo :
|
||||
fileIncludeReasonDetails,
|
||||
diagnostic,
|
||||
...args || emptyArray,
|
||||
);
|
||||
}
|
||||
|
||||
// This is chain's next contains:
|
||||
// - File is in program because:
|
||||
// - Files reasons listed
|
||||
// - extra reason if its not already processed - this happens in case sensitive file system where files differ in casing and we are giving reasons for two files so reason is not in file's reason
|
||||
// fyi above whole secton is ommited if we have single reason and we are reporting at that reason's location
|
||||
// - redirect and additional information about file
|
||||
// So cache result if we havent ommited file include reasons
|
||||
if (file) {
|
||||
if (cachedChain) {
|
||||
// Cache new fileIncludeDetails if we have update
|
||||
// Or if we had cached with more details than the reasons
|
||||
if (!cachedChain.fileIncludeReasonDetails || (!processedExtraReason && fileIncludeReasonDetails)) {
|
||||
cachedChain.fileIncludeReasonDetails = fileIncludeReasonDetails;
|
||||
}
|
||||
}
|
||||
else {
|
||||
(fileReasonsToChain ??= new Map()).set(file.path, cachedChain = { fileIncludeReasonDetails, redirectInfo });
|
||||
}
|
||||
// If we didnt compute extra file include reason , cache the details to use directly
|
||||
if (!cachedChain.details && !processedExtraReason) cachedChain.details = chain.next;
|
||||
}
|
||||
|
||||
const location = locationReason && getReferencedFileLocation(program, locationReason);
|
||||
return location && isReferenceFileLocation(location) ?
|
||||
createFileDiagnosticFromMessageChain(location.file, location.pos, location.end - location.pos, chain, relatedInfo) :
|
||||
createCompilerDiagnosticFromMessageChain(chain, relatedInfo);
|
||||
|
||||
function processReason(reason: FileIncludeReason) {
|
||||
if (seenReasons?.has(reason)) return;
|
||||
(seenReasons ??= new Set()).add(reason);
|
||||
(fileIncludeReasons ??= []).push(fileIncludeReasonToDiagnostics(program, reason));
|
||||
populateRelatedInfo(reason);
|
||||
}
|
||||
|
||||
function populateRelatedInfo(reason: FileIncludeReason) {
|
||||
if (!locationReason && isReferencedFile(reason)) {
|
||||
// Report error at first reference file or file currently in processing and dont report in related information
|
||||
locationReason = reason;
|
||||
}
|
||||
else if (locationReason !== reason) {
|
||||
relatedInfo = append(relatedInfo, getFileIncludeReasonToRelatedInformation(program, reason));
|
||||
}
|
||||
}
|
||||
|
||||
function cachedFileIncludeDetailsHasProcessedExtraReason() {
|
||||
return cachedChain!.fileIncludeReasonDetails!.next?.length !== reasons?.length;
|
||||
}
|
||||
}
|
||||
|
||||
function getFileIncludeReasonToRelatedInformation(program: Program, reason: FileIncludeReason) {
|
||||
let relatedInfo = reasonToRelatedInfo?.get(reason);
|
||||
if (relatedInfo === undefined) (reasonToRelatedInfo ??= new Map()).set(reason, relatedInfo = fileIncludeReasonToRelatedInformation(program, reason) ?? false);
|
||||
return relatedInfo || undefined;
|
||||
}
|
||||
|
||||
function fileIncludeReasonToRelatedInformation(program: Program, reason: FileIncludeReason): DiagnosticWithLocation | undefined {
|
||||
if (isReferencedFile(reason)) {
|
||||
const referenceLocation = getReferencedFileLocation(program, reason);
|
||||
let message: DiagnosticMessage;
|
||||
switch (reason.kind) {
|
||||
case FileIncludeKind.Import:
|
||||
message = Diagnostics.File_is_included_via_import_here;
|
||||
break;
|
||||
case FileIncludeKind.ReferenceFile:
|
||||
message = Diagnostics.File_is_included_via_reference_here;
|
||||
break;
|
||||
case FileIncludeKind.TypeReferenceDirective:
|
||||
message = Diagnostics.File_is_included_via_type_library_reference_here;
|
||||
break;
|
||||
case FileIncludeKind.LibReferenceDirective:
|
||||
message = Diagnostics.File_is_included_via_library_reference_here;
|
||||
break;
|
||||
default:
|
||||
Debug.assertNever(reason);
|
||||
}
|
||||
return isReferenceFileLocation(referenceLocation) ? createFileDiagnostic(
|
||||
referenceLocation.file,
|
||||
referenceLocation.pos,
|
||||
referenceLocation.end - referenceLocation.pos,
|
||||
message,
|
||||
) : undefined;
|
||||
}
|
||||
|
||||
const currentDirectory = program.getCurrentDirectory();
|
||||
const rootNames = program.getRootFileNames();
|
||||
const options = program.getCompilerOptions();
|
||||
if (!options.configFile) return undefined;
|
||||
let configFileNode: Node | undefined;
|
||||
let message: DiagnosticMessage;
|
||||
switch (reason.kind) {
|
||||
case FileIncludeKind.RootFile:
|
||||
if (!options.configFile.configFileSpecs) return undefined;
|
||||
const fileName = getNormalizedAbsolutePath(rootNames[reason.index], currentDirectory);
|
||||
const matchedByFiles = getMatchedFileSpec(program, fileName);
|
||||
if (matchedByFiles) {
|
||||
configFileNode = getTsConfigPropArrayElementValue(options.configFile, "files", matchedByFiles);
|
||||
message = Diagnostics.File_is_matched_by_files_list_specified_here;
|
||||
break;
|
||||
}
|
||||
const matchedByInclude = getMatchedIncludeSpec(program, fileName);
|
||||
// Could be additional files specified as roots
|
||||
if (!matchedByInclude || !isString(matchedByInclude)) return undefined;
|
||||
configFileNode = getTsConfigPropArrayElementValue(options.configFile, "include", matchedByInclude);
|
||||
message = Diagnostics.File_is_matched_by_include_pattern_specified_here;
|
||||
break;
|
||||
case FileIncludeKind.SourceFromProjectReference:
|
||||
case FileIncludeKind.OutputFromProjectReference:
|
||||
const resolvedProjectReferences = program.getResolvedProjectReferences();
|
||||
const projectReferences = program.getProjectReferences();
|
||||
const referencedResolvedRef = Debug.checkDefined(resolvedProjectReferences?.[reason.index]);
|
||||
const referenceInfo = forEachProjectReference(
|
||||
projectReferences,
|
||||
resolvedProjectReferences,
|
||||
(resolvedRef, parent, index) =>
|
||||
resolvedRef === referencedResolvedRef ?
|
||||
{ sourceFile: parent?.sourceFile || options.configFile!, index } :
|
||||
undefined,
|
||||
);
|
||||
if (!referenceInfo) return undefined;
|
||||
const { sourceFile, index } = referenceInfo;
|
||||
const referencesSyntax = forEachTsConfigPropArray(sourceFile as TsConfigSourceFile, "references", property => isArrayLiteralExpression(property.initializer) ? property.initializer : undefined);
|
||||
return referencesSyntax && referencesSyntax.elements.length > index ?
|
||||
createDiagnosticForNodeInSourceFile(
|
||||
sourceFile,
|
||||
referencesSyntax.elements[index],
|
||||
reason.kind === FileIncludeKind.OutputFromProjectReference ?
|
||||
Diagnostics.File_is_output_from_referenced_project_specified_here :
|
||||
Diagnostics.File_is_source_from_referenced_project_specified_here,
|
||||
) :
|
||||
undefined;
|
||||
case FileIncludeKind.AutomaticTypeDirectiveFile:
|
||||
if (!options.types) return undefined;
|
||||
configFileNode = getOptionsSyntaxByArrayElementValue(getCompilerOptionsObjectLiteralSyntax(), "types", reason.typeReference);
|
||||
message = Diagnostics.File_is_entry_point_of_type_library_specified_here;
|
||||
break;
|
||||
case FileIncludeKind.LibFile:
|
||||
if (reason.index !== undefined) {
|
||||
configFileNode = getOptionsSyntaxByArrayElementValue(getCompilerOptionsObjectLiteralSyntax(), "lib", options.lib![reason.index]);
|
||||
message = Diagnostics.File_is_library_specified_here;
|
||||
break;
|
||||
}
|
||||
const target = getNameOfScriptTarget(getEmitScriptTarget(options));
|
||||
configFileNode = target ? getOptionsSyntaxByValue(getCompilerOptionsObjectLiteralSyntax(), "target", target) : undefined;
|
||||
message = Diagnostics.File_is_default_library_for_target_specified_here;
|
||||
break;
|
||||
default:
|
||||
Debug.assertNever(reason);
|
||||
}
|
||||
return configFileNode && createDiagnosticForNodeInSourceFile(
|
||||
options.configFile,
|
||||
configFileNode,
|
||||
message,
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -13,6 +13,7 @@ import {
|
||||
PackageJsonInfo,
|
||||
PackageJsonInfoCache,
|
||||
Pattern,
|
||||
ProgramDiagnostics,
|
||||
SymlinkCache,
|
||||
ThisContainer,
|
||||
} from "./_namespaces/ts.js";
|
||||
@ -4892,6 +4893,7 @@ export interface Program extends ScriptReferenceHost {
|
||||
* @internal
|
||||
*/
|
||||
resolvedLibReferences: Map<string, LibResolution> | undefined;
|
||||
/** @internal */ getProgramDiagnosticsContainer: () => ProgramDiagnostics;
|
||||
/** @internal */ getCurrentPackagesMap(): Map<string, boolean> | undefined;
|
||||
/**
|
||||
* Is the file emitted file
|
||||
|
||||
@ -138,6 +138,7 @@ import {
|
||||
FileExtensionInfo,
|
||||
fileExtensionIs,
|
||||
fileExtensionIsOneOf,
|
||||
FileReference,
|
||||
FileWatcher,
|
||||
filter,
|
||||
find,
|
||||
@ -408,6 +409,7 @@ import {
|
||||
lastOrUndefined,
|
||||
LateVisibilityPaintedStatement,
|
||||
length,
|
||||
libMap,
|
||||
LiteralImportTypeNode,
|
||||
LiteralLikeElementAccessExpression,
|
||||
LiteralLikeNode,
|
||||
@ -497,6 +499,7 @@ import {
|
||||
ResolutionMode,
|
||||
ResolvedModuleFull,
|
||||
ResolvedModuleWithFailedLookupLocations,
|
||||
ResolvedProjectReference,
|
||||
ResolvedTypeReferenceDirective,
|
||||
ResolvedTypeReferenceDirectiveWithFailedLookupLocations,
|
||||
resolvePath,
|
||||
@ -549,6 +552,7 @@ import {
|
||||
TextRange,
|
||||
TextSpan,
|
||||
ThisTypePredicate,
|
||||
toFileNameLowerCase,
|
||||
Token,
|
||||
TokenFlags,
|
||||
tokenToString,
|
||||
@ -3016,14 +3020,6 @@ export function forEachPropertyAssignment<T>(objectLiteral: ObjectLiteralExpress
|
||||
});
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function getPropertyArrayElementValue(objectLiteral: ObjectLiteralExpression, propKey: string, elementValue: string): StringLiteral | undefined {
|
||||
return forEachPropertyAssignment(objectLiteral, propKey, property =>
|
||||
isArrayLiteralExpression(property.initializer) ?
|
||||
find(property.initializer.elements, (element): element is StringLiteral => isStringLiteral(element) && element.text === elementValue) :
|
||||
undefined);
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function getTsConfigObjectLiteralExpression(tsConfigSourceFile: TsConfigSourceFile | undefined): ObjectLiteralExpression | undefined {
|
||||
if (tsConfigSourceFile && tsConfigSourceFile.statements.length) {
|
||||
@ -12113,3 +12109,91 @@ export function isNewScopeNode(node: Node): node is IntroducesNewScopeNode {
|
||||
|| isJSDocSignature(node)
|
||||
|| isMappedTypeNode(node);
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function getLibNameFromLibReference(libReference: FileReference): string {
|
||||
return toFileNameLowerCase(libReference.fileName);
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function getLibFileNameFromLibReference(libReference: FileReference): string | undefined {
|
||||
const libName = getLibNameFromLibReference(libReference);
|
||||
return libMap.get(libName);
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function forEachResolvedProjectReference<T>(
|
||||
resolvedProjectReferences: readonly (ResolvedProjectReference | undefined)[] | undefined,
|
||||
cb: (resolvedProjectReference: ResolvedProjectReference, parent: ResolvedProjectReference | undefined) => T | undefined,
|
||||
): T | undefined {
|
||||
return forEachProjectReference(
|
||||
/*projectReferences*/ undefined,
|
||||
resolvedProjectReferences,
|
||||
(resolvedRef, parent) => resolvedRef && cb(resolvedRef, parent),
|
||||
);
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function forEachProjectReference<T>(
|
||||
projectReferences: readonly ProjectReference[] | undefined,
|
||||
resolvedProjectReferences: readonly (ResolvedProjectReference | undefined)[] | undefined,
|
||||
cbResolvedRef: (resolvedRef: ResolvedProjectReference | undefined, parent: ResolvedProjectReference | undefined, index: number) => T | undefined,
|
||||
cbRef?: (projectReferences: readonly ProjectReference[] | undefined, parent: ResolvedProjectReference | undefined) => T | undefined,
|
||||
): T | undefined {
|
||||
let seenResolvedRefs: Set<Path> | undefined;
|
||||
return worker(projectReferences, resolvedProjectReferences, /*parent*/ undefined);
|
||||
|
||||
function worker(
|
||||
projectReferences: readonly ProjectReference[] | undefined,
|
||||
resolvedProjectReferences: readonly (ResolvedProjectReference | undefined)[] | undefined,
|
||||
parent: ResolvedProjectReference | undefined,
|
||||
): T | undefined {
|
||||
// Visit project references first
|
||||
if (cbRef) {
|
||||
const result = cbRef(projectReferences, parent);
|
||||
if (result) return result;
|
||||
}
|
||||
let skipChildren: Set<ResolvedProjectReference> | undefined;
|
||||
return forEach(
|
||||
resolvedProjectReferences,
|
||||
(resolvedRef, index) => {
|
||||
if (resolvedRef && seenResolvedRefs?.has(resolvedRef.sourceFile.path)) {
|
||||
(skipChildren ??= new Set()).add(resolvedRef);
|
||||
// ignore recursives
|
||||
return undefined;
|
||||
}
|
||||
const result = cbResolvedRef(resolvedRef, parent, index);
|
||||
if (result || !resolvedRef) return result;
|
||||
(seenResolvedRefs ||= new Set()).add(resolvedRef.sourceFile.path);
|
||||
},
|
||||
) || forEach(
|
||||
resolvedProjectReferences,
|
||||
resolvedRef =>
|
||||
resolvedRef && !skipChildren?.has(resolvedRef) ?
|
||||
worker(resolvedRef.commandLine.projectReferences, resolvedRef.references, resolvedRef) :
|
||||
undefined,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function getOptionsSyntaxByArrayElementValue(optionsObject: ObjectLiteralExpression | undefined, name: string, value: string): StringLiteral | undefined {
|
||||
return optionsObject && getPropertyArrayElementValue(optionsObject, name, value);
|
||||
}
|
||||
|
||||
function getPropertyArrayElementValue(objectLiteral: ObjectLiteralExpression, propKey: string, elementValue: string): StringLiteral | undefined {
|
||||
return forEachPropertyAssignment(objectLiteral, propKey, property =>
|
||||
isArrayLiteralExpression(property.initializer) ?
|
||||
find(property.initializer.elements, (element): element is StringLiteral => isStringLiteral(element) && element.text === elementValue) :
|
||||
undefined);
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function getOptionsSyntaxByValue(optionsObject: ObjectLiteralExpression | undefined, name: string, value: string): StringLiteral | undefined {
|
||||
return forEachOptionsSyntaxByName(optionsObject, name, property => isStringLiteral(property.initializer) && property.initializer.text === value ? property.initializer : undefined);
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function forEachOptionsSyntaxByName<T>(optionsObject: ObjectLiteralExpression | undefined, name: string, callback: (prop: PropertyAssignment) => T | undefined): T | undefined {
|
||||
return forEachPropertyAssignment(optionsObject, name, callback);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user