mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-03-16 06:28:12 -05:00
Add TS Server option to exclude files from auto-imports (#49578)
* Basic functionality * Add tests * Add test for ambient modules * Add to protocol
This commit is contained in:
@@ -413,7 +413,7 @@ namespace ts.codefix {
|
||||
return createModuleSpecifierResolutionHost(isFromPackageJson ? host.getPackageJsonAutoImportProvider!()! : program, host);
|
||||
});
|
||||
|
||||
forEachExternalModuleToImportFrom(program, host, useAutoImportProvider, (moduleSymbol, moduleFile, program, isFromPackageJson) => {
|
||||
forEachExternalModuleToImportFrom(program, host, preferences, useAutoImportProvider, (moduleSymbol, moduleFile, program, isFromPackageJson) => {
|
||||
const checker = program.getTypeChecker();
|
||||
// Don't import from a re-export when looking "up" like to `./index` or `../index`.
|
||||
if (moduleFile && moduleSymbol !== exportingModuleSymbol && startsWith(importingFile.fileName, getDirectoryPath(moduleFile.fileName))) {
|
||||
@@ -979,7 +979,7 @@ namespace ts.codefix {
|
||||
originalSymbolToExportInfos.add(getUniqueSymbolId(exportedSymbol, checker).toString(), { symbol: exportedSymbol, moduleSymbol, moduleFileName: toFile?.fileName, exportKind, targetFlags: skipAlias(exportedSymbol, checker).flags, isFromPackageJson });
|
||||
}
|
||||
}
|
||||
forEachExternalModuleToImportFrom(program, host, useAutoImportProvider, (moduleSymbol, sourceFile, program, isFromPackageJson) => {
|
||||
forEachExternalModuleToImportFrom(program, host, preferences, useAutoImportProvider, (moduleSymbol, sourceFile, program, isFromPackageJson) => {
|
||||
const checker = program.getTypeChecker();
|
||||
cancellationToken.throwIfCancellationRequested();
|
||||
|
||||
|
||||
@@ -366,7 +366,7 @@ namespace ts.Completions {
|
||||
if (!previousResponse) return undefined;
|
||||
|
||||
const lowerCaseTokenText = location.text.toLowerCase();
|
||||
const exportMap = getExportInfoMap(file, host, program, cancellationToken);
|
||||
const exportMap = getExportInfoMap(file, host, program, preferences, cancellationToken);
|
||||
const newEntries = resolvingModuleSpecifiers(
|
||||
"continuePreviousIncompleteResponse",
|
||||
host,
|
||||
@@ -2725,7 +2725,7 @@ namespace ts.Completions {
|
||||
"";
|
||||
|
||||
const moduleSpecifierCache = host.getModuleSpecifierCache?.();
|
||||
const exportInfo = getExportInfoMap(sourceFile, host, program, cancellationToken);
|
||||
const exportInfo = getExportInfoMap(sourceFile, host, program, preferences, cancellationToken);
|
||||
const packageJsonAutoImportProvider = host.getPackageJsonAutoImportProvider?.();
|
||||
const packageJsonFilter = detailsEntryId ? undefined : createPackageJsonImportFilter(sourceFile, preferences, host);
|
||||
resolvingModuleSpecifiers(
|
||||
|
||||
@@ -336,32 +336,42 @@ namespace ts {
|
||||
export function forEachExternalModuleToImportFrom(
|
||||
program: Program,
|
||||
host: LanguageServiceHost,
|
||||
preferences: UserPreferences,
|
||||
useAutoImportProvider: boolean,
|
||||
cb: (module: Symbol, moduleFile: SourceFile | undefined, program: Program, isFromPackageJson: boolean) => void,
|
||||
) {
|
||||
forEachExternalModule(program.getTypeChecker(), program.getSourceFiles(), (module, file) => cb(module, file, program, /*isFromPackageJson*/ false));
|
||||
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 = getPatternFromSpec(spec, "", "exclude");
|
||||
return pattern ? getRegexFromPattern(pattern, useCaseSensitiveFileNames) : undefined;
|
||||
});
|
||||
|
||||
forEachExternalModule(program.getTypeChecker(), program.getSourceFiles(), excludePatterns, (module, file) => cb(module, file, program, /*isFromPackageJson*/ false));
|
||||
const autoImportProvider = useAutoImportProvider && host.getPackageJsonAutoImportProvider?.();
|
||||
if (autoImportProvider) {
|
||||
const start = timestamp();
|
||||
forEachExternalModule(autoImportProvider.getTypeChecker(), autoImportProvider.getSourceFiles(), (module, file) => cb(module, file, autoImportProvider, /*isFromPackageJson*/ true));
|
||||
forEachExternalModule(autoImportProvider.getTypeChecker(), autoImportProvider.getSourceFiles(), excludePatterns, (module, file) => cb(module, file, autoImportProvider, /*isFromPackageJson*/ true));
|
||||
host.log?.(`forEachExternalModuleToImportFrom autoImportProvider: ${timestamp() - start}`);
|
||||
}
|
||||
}
|
||||
|
||||
function forEachExternalModule(checker: TypeChecker, allSourceFiles: readonly SourceFile[], cb: (module: Symbol, sourceFile: SourceFile | undefined) => void) {
|
||||
function forEachExternalModule(checker: TypeChecker, allSourceFiles: readonly SourceFile[], excludePatterns: readonly RegExp[] | undefined, cb: (module: Symbol, sourceFile: SourceFile | undefined) => void) {
|
||||
const isExcluded = (fileName: string) => excludePatterns?.some(p => p.test(fileName));
|
||||
for (const ambient of checker.getAmbientModules()) {
|
||||
if (!stringContains(ambient.name, "*")) {
|
||||
if (!stringContains(ambient.name, "*") && !(excludePatterns && ambient.declarations?.every(d => isExcluded(d.getSourceFile().fileName)))) {
|
||||
cb(ambient, /*sourceFile*/ undefined);
|
||||
}
|
||||
}
|
||||
for (const sourceFile of allSourceFiles) {
|
||||
if (isExternalOrCommonJsModule(sourceFile)) {
|
||||
if (isExternalOrCommonJsModule(sourceFile) && !isExcluded(sourceFile.fileName)) {
|
||||
cb(checker.getMergedSymbol(sourceFile.symbol), sourceFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function getExportInfoMap(importingFile: SourceFile, host: LanguageServiceHost, program: Program, cancellationToken: CancellationToken | undefined): ExportInfoMap {
|
||||
export function getExportInfoMap(importingFile: SourceFile, host: LanguageServiceHost, program: Program, preferences: UserPreferences, cancellationToken: CancellationToken | undefined): ExportInfoMap {
|
||||
const start = timestamp();
|
||||
// Pulling the AutoImportProvider project will trigger its updateGraph if pending,
|
||||
// which will invalidate the export map cache if things change, so pull it before
|
||||
@@ -382,7 +392,7 @@ namespace ts {
|
||||
const compilerOptions = program.getCompilerOptions();
|
||||
let moduleCount = 0;
|
||||
try {
|
||||
forEachExternalModuleToImportFrom(program, host, /*useAutoImportProvider*/ true, (moduleSymbol, moduleFile, program, isFromPackageJson) => {
|
||||
forEachExternalModuleToImportFrom(program, host, preferences, /*useAutoImportProvider*/ true, (moduleSymbol, moduleFile, program, isFromPackageJson) => {
|
||||
if (++moduleCount % 100 === 0) cancellationToken?.throwIfCancellationRequested();
|
||||
const seenExports = new Map<__String, true>();
|
||||
const checker = program.getTypeChecker();
|
||||
|
||||
Reference in New Issue
Block a user