mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-05-30 01:04:49 -05:00
fix55816: exclude files with re-exports if excluded by preferences.autoImportFileExcludePatterns (#58537)
Co-authored-by: Andrew Branch <andrewbranch@users.noreply.github.com>
This commit is contained in:
@@ -47,12 +47,14 @@ import {
|
||||
FutureSymbolExportInfo,
|
||||
getAllowSyntheticDefaultImports,
|
||||
getBaseFileName,
|
||||
getDeclarationOfKind,
|
||||
getDefaultLikeExportInfo,
|
||||
getDirectoryPath,
|
||||
getEmitModuleKind,
|
||||
getEmitModuleResolutionKind,
|
||||
getEmitScriptTarget,
|
||||
getExportInfoMap,
|
||||
getIsFileExcluded,
|
||||
getMeaningFromLocation,
|
||||
getNameForExportedSymbol,
|
||||
getOutputExtension,
|
||||
@@ -277,8 +279,14 @@ function createImportAdderWorker(sourceFile: SourceFile | FutureSourceFile, prog
|
||||
const checker = program.getTypeChecker();
|
||||
const symbol = checker.getMergedSymbol(skipAlias(exportedSymbol, checker));
|
||||
const exportInfo = getAllExportInfoForSymbol(sourceFile, symbol, symbolName, moduleSymbol, /*preferCapitalized*/ false, program, host, preferences, cancellationToken);
|
||||
if (!exportInfo) {
|
||||
// If no exportInfo is found, this means export could not be resolved when we have filtered for autoImportFileExcludePatterns,
|
||||
// so we should not generate an import.
|
||||
Debug.assert(preferences.autoImportFileExcludePatterns?.length);
|
||||
return;
|
||||
}
|
||||
const useRequire = shouldUseRequire(sourceFile, program);
|
||||
let fix = getImportFixForSymbol(sourceFile, Debug.checkDefined(exportInfo), program, /*position*/ undefined, !!isValidTypeOnlyUseSite, useRequire, host, preferences);
|
||||
let fix = getImportFixForSymbol(sourceFile, exportInfo, program, /*position*/ undefined, !!isValidTypeOnlyUseSite, useRequire, host, preferences);
|
||||
if (fix) {
|
||||
const localName = tryCast(referenceImport?.name, isIdentifier)?.text ?? symbolName;
|
||||
if (
|
||||
@@ -859,9 +867,16 @@ function codeFixActionToCodeAction({ description, changes, commands }: CodeFixAc
|
||||
|
||||
function getAllExportInfoForSymbol(importingFile: SourceFile | FutureSourceFile, symbol: Symbol, symbolName: string, moduleSymbol: Symbol, preferCapitalized: boolean, program: Program, host: LanguageServiceHost, preferences: UserPreferences, cancellationToken: CancellationToken | undefined): readonly SymbolExportInfo[] | undefined {
|
||||
const getChecker = createGetChecker(program, host);
|
||||
const isFileExcluded = preferences.autoImportFileExcludePatterns && getIsFileExcluded(host, preferences);
|
||||
const mergedModuleSymbol = program.getTypeChecker().getMergedSymbol(moduleSymbol);
|
||||
const moduleSourceFile = isFileExcluded && mergedModuleSymbol.declarations && getDeclarationOfKind(mergedModuleSymbol, SyntaxKind.SourceFile);
|
||||
const moduleSymbolExcluded = moduleSourceFile && isFileExcluded(moduleSourceFile as SourceFile);
|
||||
return getExportInfoMap(importingFile, host, program, preferences, cancellationToken)
|
||||
.search(importingFile.path, preferCapitalized, name => name === symbolName, info => {
|
||||
if (skipAlias(info[0].symbol, getChecker(info[0].isFromPackageJson)) === symbol && info.some(i => i.moduleSymbol === moduleSymbol || i.symbol.parent === moduleSymbol)) {
|
||||
if (
|
||||
getChecker(info[0].isFromPackageJson).getMergedSymbol(skipAlias(info[0].symbol, getChecker(info[0].isFromPackageJson))) === symbol
|
||||
&& (moduleSymbolExcluded || info.some(i => i.moduleSymbol === moduleSymbol || i.symbol.parent === moduleSymbol))
|
||||
) {
|
||||
return info;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -426,12 +426,7 @@ export function forEachExternalModuleToImportFrom(
|
||||
cb: (module: Symbol, moduleFile: SourceFile | undefined, program: Program, isFromPackageJson: boolean) => void,
|
||||
) {
|
||||
const useCaseSensitiveFileNames = hostUsesCaseSensitiveFileNames(host);
|
||||
const excludePatterns = preferences.autoImportFileExcludePatterns && mapDefined(preferences.autoImportFileExcludePatterns, spec => {
|
||||
// The client is expected to send rooted path specs since we don't know
|
||||
// what directory a relative path is relative to.
|
||||
const pattern = getSubPatternFromSpec(spec, "", "exclude");
|
||||
return pattern ? getRegexFromPattern(pattern, useCaseSensitiveFileNames) : undefined;
|
||||
});
|
||||
const excludePatterns = preferences.autoImportFileExcludePatterns && getIsExcludedPatterns(preferences, useCaseSensitiveFileNames);
|
||||
|
||||
forEachExternalModule(program.getTypeChecker(), program.getSourceFiles(), excludePatterns, host, (module, file) => cb(module, file, program, /*isFromPackageJson*/ false));
|
||||
const autoImportProvider = useAutoImportProvider && host.getPackageJsonAutoImportProvider?.();
|
||||
@@ -451,9 +446,33 @@ export function forEachExternalModuleToImportFrom(
|
||||
}
|
||||
}
|
||||
|
||||
function getIsExcludedPatterns(preferences: UserPreferences, useCaseSensitiveFileNames: boolean) {
|
||||
return mapDefined(preferences.autoImportFileExcludePatterns, spec => {
|
||||
// The client is expected to send rooted path specs since we don't know
|
||||
// what directory a relative path is relative to.
|
||||
const pattern = getSubPatternFromSpec(spec, "", "exclude");
|
||||
return pattern ? getRegexFromPattern(pattern, useCaseSensitiveFileNames) : undefined;
|
||||
});
|
||||
}
|
||||
|
||||
function forEachExternalModule(checker: TypeChecker, allSourceFiles: readonly SourceFile[], excludePatterns: readonly RegExp[] | undefined, host: LanguageServiceHost, cb: (module: Symbol, sourceFile: SourceFile | undefined) => void) {
|
||||
const isExcluded = excludePatterns && getIsExcluded(excludePatterns, host);
|
||||
|
||||
for (const ambient of checker.getAmbientModules()) {
|
||||
if (!ambient.name.includes("*") && !(excludePatterns && ambient.declarations?.every(d => isExcluded!(d.getSourceFile())))) {
|
||||
cb(ambient, /*sourceFile*/ undefined);
|
||||
}
|
||||
}
|
||||
for (const sourceFile of allSourceFiles) {
|
||||
if (isExternalOrCommonJsModule(sourceFile) && !isExcluded?.(sourceFile)) {
|
||||
cb(checker.getMergedSymbol(sourceFile.symbol), sourceFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getIsExcluded(excludePatterns: readonly RegExp[], host: LanguageServiceHost) {
|
||||
const realpathsWithSymlinks = host.getSymlinkCache?.().getSymlinkedDirectoriesByRealpath();
|
||||
const isExcluded = excludePatterns && (({ fileName, path }: SourceFile) => {
|
||||
return (({ fileName, path }: SourceFile) => {
|
||||
if (excludePatterns.some(p => p.test(fileName))) return true;
|
||||
if (realpathsWithSymlinks?.size && pathContainsNodeModules(fileName)) {
|
||||
let dir = getDirectoryPath(fileName);
|
||||
@@ -467,17 +486,12 @@ function forEachExternalModule(checker: TypeChecker, allSourceFiles: readonly So
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
for (const ambient of checker.getAmbientModules()) {
|
||||
if (!ambient.name.includes("*") && !(excludePatterns && ambient.declarations?.every(d => isExcluded!(d.getSourceFile())))) {
|
||||
cb(ambient, /*sourceFile*/ undefined);
|
||||
}
|
||||
}
|
||||
for (const sourceFile of allSourceFiles) {
|
||||
if (isExternalOrCommonJsModule(sourceFile) && !isExcluded?.(sourceFile)) {
|
||||
cb(checker.getMergedSymbol(sourceFile.symbol), sourceFile);
|
||||
}
|
||||
}
|
||||
/** @internal */
|
||||
export function getIsFileExcluded(host: LanguageServiceHost, preferences: UserPreferences) {
|
||||
if (!preferences.autoImportFileExcludePatterns) return () => false;
|
||||
return getIsExcluded(getIsExcludedPatterns(preferences, hostUsesCaseSensitiveFileNames(host)), host);
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
|
||||
Reference in New Issue
Block a user