mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-04 21:53:42 -06:00
Better reuse of package.json cache, module resolution cache, and package.json auto import filter (#47388)
* Use package.json cache in module specifier generation * Let AutoImportProviderProject reuse module resolution cache of host project * Add missing module resolution cache access, add logging to getRootFileNames * Reuse packageJsonImportFilter * Only log when the project will be created, update API baseline * Remove override that could mess up watches
This commit is contained in:
parent
8153475ca5
commit
d0b3ac376d
@ -4722,6 +4722,7 @@ namespace ts {
|
||||
getCommonSourceDirectory: !!(host as Program).getCommonSourceDirectory ? () => (host as Program).getCommonSourceDirectory() : () => "",
|
||||
getCurrentDirectory: () => host.getCurrentDirectory(),
|
||||
getSymlinkCache: maybeBind(host, host.getSymlinkCache),
|
||||
getPackageJsonInfoCache: () => host.getPackageJsonInfoCache?.(),
|
||||
useCaseSensitiveFileNames: maybeBind(host, host.useCaseSensitiveFileNames),
|
||||
redirectTargetsMap: host.redirectTargetsMap,
|
||||
getProjectReferenceRedirect: fileName => host.getProjectReferenceRedirect(fileName),
|
||||
|
||||
@ -45,7 +45,7 @@ namespace ts.moduleSpecifiers {
|
||||
&& getEmitModuleResolutionKind(compilerOptions) !== ModuleResolutionKind.NodeNext) {
|
||||
return false;
|
||||
}
|
||||
return getImpliedNodeFormatForFile(importingSourceFileName, /*packageJsonInfoCache*/ undefined, getModuleResolutionHost(host), compilerOptions) !== ModuleKind.CommonJS;
|
||||
return getImpliedNodeFormatForFile(importingSourceFileName, host.getPackageJsonInfoCache?.(), getModuleResolutionHost(host), compilerOptions) !== ModuleKind.CommonJS;
|
||||
}
|
||||
|
||||
function getModuleResolutionHost(host: ModuleSpecifierResolutionHost): ModuleResolutionHost {
|
||||
@ -715,8 +715,9 @@ namespace ts.moduleSpecifiers {
|
||||
const packageRootPath = path.substring(0, packageRootIndex);
|
||||
const packageJsonPath = combinePaths(packageRootPath, "package.json");
|
||||
let moduleFileToTry = path;
|
||||
if (host.fileExists(packageJsonPath)) {
|
||||
const packageJsonContent = JSON.parse(host.readFile!(packageJsonPath)!);
|
||||
const cachedPackageJson = host.getPackageJsonInfoCache?.()?.getPackageJsonInfo(packageJsonPath);
|
||||
if (typeof cachedPackageJson === "object" || cachedPackageJson === undefined && host.fileExists(packageJsonPath)) {
|
||||
const packageJsonContent = cachedPackageJson?.packageJsonContent || JSON.parse(host.readFile!(packageJsonPath)!);
|
||||
if (getEmitModuleResolutionKind(options) === ModuleResolutionKind.Node12 || getEmitModuleResolutionKind(options) === ModuleResolutionKind.NodeNext) {
|
||||
// `conditions` *could* be made to go against `importingSourceFile.impliedNodeFormat` if something wanted to generate
|
||||
// an ImportEqualsDeclaration in an ESM-implied file or an ImportCall in a CJS-implied file. But since this function is
|
||||
|
||||
@ -8345,6 +8345,7 @@ namespace ts {
|
||||
realpath?(path: string): string;
|
||||
getSymlinkCache?(): SymlinkCache;
|
||||
getModuleSpecifierCache?(): ModuleSpecifierCache;
|
||||
getPackageJsonInfoCache?(): PackageJsonInfoCache | undefined;
|
||||
getGlobalTypingsCacheLocation?(): string | undefined;
|
||||
getNearestAncestorDirectoryWithPackageJson?(fileName: string, rootDir?: string): string | undefined;
|
||||
|
||||
|
||||
@ -476,6 +476,10 @@ namespace ts.server {
|
||||
return this.resolutionCache.resolveModuleNames(moduleNames, containingFile, reusedNames, redirectedReference, containingSourceFile);
|
||||
}
|
||||
|
||||
getModuleResolutionCache(): ModuleResolutionCache | undefined {
|
||||
return this.resolutionCache.getModuleResolutionCache();
|
||||
}
|
||||
|
||||
getResolvedModuleWithFailedLookupLocationsFromCache(moduleName: string, containingFile: string, resolutionMode?: ModuleKind.CommonJS | ModuleKind.ESNext): ResolvedModuleWithFailedLookupLocations | undefined {
|
||||
return this.resolutionCache.getResolvedModuleWithFailedLookupLocationsFromCache(moduleName, containingFile, resolutionMode);
|
||||
}
|
||||
@ -1915,6 +1919,7 @@ namespace ts.server {
|
||||
return ts.emptyArray;
|
||||
}
|
||||
|
||||
const start = timestamp();
|
||||
let dependencyNames: Set<string> | undefined;
|
||||
let rootNames: string[] | undefined;
|
||||
const rootFileName = combinePaths(hostProject.currentDirectory, inferredTypesContainingFile);
|
||||
@ -1924,13 +1929,13 @@ namespace ts.server {
|
||||
packageJson.peerDependencies?.forEach((_, dependencyName) => addDependency(dependencyName));
|
||||
}
|
||||
|
||||
let dependenciesAdded = 0;
|
||||
if (dependencyNames) {
|
||||
let dependenciesAdded = 0;
|
||||
const symlinkCache = hostProject.getSymlinkCache();
|
||||
for (const name of arrayFrom(dependencyNames.keys())) {
|
||||
// Avoid creating a large project that would significantly slow down time to editor interactivity
|
||||
if (dependencySelection === PackageJsonAutoImportPreference.Auto && dependenciesAdded > this.maxDependencies) {
|
||||
hostProject.log(`Auto-import provider attempted to add more than ${this.maxDependencies} dependencies.`);
|
||||
hostProject.log(`AutoImportProviderProject: attempted to add more than ${this.maxDependencies} dependencies. Aborting.`);
|
||||
return ts.emptyArray;
|
||||
}
|
||||
|
||||
@ -1978,6 +1983,9 @@ namespace ts.server {
|
||||
}
|
||||
}
|
||||
|
||||
if (rootNames?.length) {
|
||||
hostProject.log(`AutoImportProviderProject: found ${rootNames.length} root files in ${dependenciesAdded} dependencies in ${timestamp() - start} ms`);
|
||||
}
|
||||
return rootNames || ts.emptyArray;
|
||||
|
||||
function addDependency(dependency: string) {
|
||||
@ -2146,6 +2154,11 @@ namespace ts.server {
|
||||
getSymlinkCache() {
|
||||
return this.hostProject.getSymlinkCache();
|
||||
}
|
||||
|
||||
/*@internal*/
|
||||
getModuleResolutionCache() {
|
||||
return this.hostProject.getCurrentProgram()?.getModuleResolutionCache();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -303,7 +303,8 @@ namespace ts.codefix {
|
||||
|
||||
function getImportFixForSymbol(sourceFile: SourceFile, exportInfos: readonly SymbolExportInfo[], moduleSymbol: Symbol, symbolName: string, program: Program, position: number | undefined, isValidTypeOnlyUseSite: boolean, useRequire: boolean, host: LanguageServiceHost, preferences: UserPreferences) {
|
||||
Debug.assert(exportInfos.some(info => info.moduleSymbol === moduleSymbol || info.symbol.parent === moduleSymbol), "Some exportInfo should match the specified moduleSymbol");
|
||||
return getBestFix(getImportFixes(exportInfos, symbolName, position, isValidTypeOnlyUseSite, useRequire, program, sourceFile, host, preferences), sourceFile, program, host, preferences);
|
||||
const packageJsonImportFilter = createPackageJsonImportFilter(sourceFile, preferences, host);
|
||||
return getBestFix(getImportFixes(exportInfos, symbolName, position, isValidTypeOnlyUseSite, useRequire, program, sourceFile, host, preferences), sourceFile, program, packageJsonImportFilter);
|
||||
}
|
||||
|
||||
function codeFixActionToCodeAction({ description, changes, commands }: CodeFixAction): CodeAction {
|
||||
@ -369,6 +370,7 @@ namespace ts.codefix {
|
||||
program: Program,
|
||||
host: LanguageServiceHost,
|
||||
preferences: UserPreferences,
|
||||
packageJsonImportFilter?: PackageJsonImportFilter,
|
||||
fromCacheOnly?: boolean,
|
||||
): { exportInfo?: SymbolExportInfo, moduleSpecifier: string, computedWithoutCacheCount: number } | undefined {
|
||||
const { fixes, computedWithoutCacheCount } = getNewImportFixes(
|
||||
@ -381,7 +383,7 @@ namespace ts.codefix {
|
||||
host,
|
||||
preferences,
|
||||
fromCacheOnly);
|
||||
const result = getBestFix(fixes, importingFile, program, host, preferences);
|
||||
const result = getBestFix(fixes, importingFile, program, packageJsonImportFilter || createPackageJsonImportFilter(importingFile, preferences, host));
|
||||
return result && { ...result, computedWithoutCacheCount };
|
||||
}
|
||||
|
||||
@ -652,24 +654,23 @@ namespace ts.codefix {
|
||||
const info = errorCode === Diagnostics._0_refers_to_a_UMD_global_but_the_current_file_is_a_module_Consider_adding_an_import_instead.code
|
||||
? getFixesInfoForUMDImport(context, symbolToken)
|
||||
: isIdentifier(symbolToken) ? getFixesInfoForNonUMDImport(context, symbolToken, useAutoImportProvider) : undefined;
|
||||
return info && { ...info, fixes: sortFixes(info.fixes, context.sourceFile, context.program, context.host, context.preferences) };
|
||||
const packageJsonImportFilter = createPackageJsonImportFilter(context.sourceFile, context.preferences, context.host);
|
||||
return info && { ...info, fixes: sortFixes(info.fixes, context.sourceFile, context.program, packageJsonImportFilter) };
|
||||
}
|
||||
|
||||
function sortFixes(fixes: readonly ImportFix[], sourceFile: SourceFile, program: Program, host: LanguageServiceHost, preferences: UserPreferences): readonly ImportFix[] {
|
||||
const { allowsImportingSpecifier } = createPackageJsonImportFilter(sourceFile, preferences, host);
|
||||
return sort(fixes, (a, b) => compareValues(a.kind, b.kind) || compareModuleSpecifiers(a, b, sourceFile, program, allowsImportingSpecifier));
|
||||
function sortFixes(fixes: readonly ImportFix[], sourceFile: SourceFile, program: Program, packageJsonImportFilter: PackageJsonImportFilter): readonly ImportFix[] {
|
||||
return sort(fixes, (a, b) => compareValues(a.kind, b.kind) || compareModuleSpecifiers(a, b, sourceFile, program, packageJsonImportFilter.allowsImportingSpecifier));
|
||||
}
|
||||
|
||||
function getBestFix<T extends ImportFix>(fixes: readonly T[], sourceFile: SourceFile, program: Program, host: LanguageServiceHost, preferences: UserPreferences): T | undefined {
|
||||
function getBestFix<T extends ImportFix>(fixes: readonly T[], sourceFile: SourceFile, program: Program, packageJsonImportFilter: PackageJsonImportFilter): T | undefined {
|
||||
if (!some(fixes)) return;
|
||||
// These will always be placed first if available, and are better than other kinds
|
||||
if (fixes[0].kind === ImportFixKind.UseNamespace || fixes[0].kind === ImportFixKind.AddToExisting) {
|
||||
return fixes[0];
|
||||
}
|
||||
const { allowsImportingSpecifier } = createPackageJsonImportFilter(sourceFile, preferences, host);
|
||||
return fixes.reduce((best, fix) =>
|
||||
// Takes true branch of conditional if `fix` is better than `best`
|
||||
compareModuleSpecifiers(fix, best, sourceFile, program, allowsImportingSpecifier) === Comparison.LessThan ? fix : best
|
||||
compareModuleSpecifiers(fix, best, sourceFile, program, packageJsonImportFilter.allowsImportingSpecifier) === Comparison.LessThan ? fix : best
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -177,6 +177,7 @@ namespace ts.Completions {
|
||||
cb: (context: ModuleSpecifierResolutioContext) => TReturn,
|
||||
): TReturn {
|
||||
const start = timestamp();
|
||||
const packageJsonImportFilter = createPackageJsonImportFilter(sourceFile, preferences, host);
|
||||
let resolutionLimitExceeded = false;
|
||||
let ambientCount = 0;
|
||||
let resolvedCount = 0;
|
||||
@ -202,7 +203,7 @@ namespace ts.Completions {
|
||||
const shouldResolveModuleSpecifier = isForImportStatementCompletion || preferences.allowIncompleteCompletions && resolvedCount < moduleSpecifierResolutionLimit;
|
||||
const shouldGetModuleSpecifierFromCache = !shouldResolveModuleSpecifier && preferences.allowIncompleteCompletions && cacheAttemptCount < moduleSpecifierResolutionCacheAttemptLimit;
|
||||
const result = (shouldResolveModuleSpecifier || shouldGetModuleSpecifierFromCache)
|
||||
? codefix.getModuleSpecifierForBestExportInfo(exportInfo, sourceFile, program, host, preferences, shouldGetModuleSpecifierFromCache)
|
||||
? codefix.getModuleSpecifierForBestExportInfo(exportInfo, sourceFile, program, host, preferences, packageJsonImportFilter, shouldGetModuleSpecifierFromCache)
|
||||
: undefined;
|
||||
|
||||
if (!shouldResolveModuleSpecifier && !shouldGetModuleSpecifierFromCache || shouldGetModuleSpecifierFromCache && !result) {
|
||||
|
||||
@ -1376,6 +1376,7 @@ namespace ts {
|
||||
hasChangedAutomaticTypeDirectiveNames,
|
||||
trace: parseConfigHost.trace,
|
||||
resolveModuleNames: maybeBind(host, host.resolveModuleNames),
|
||||
getModuleResolutionCache: maybeBind(host, host.getModuleResolutionCache),
|
||||
resolveTypeReferenceDirectives: maybeBind(host, host.resolveTypeReferenceDirectives),
|
||||
useSourceOfProjectReferenceRedirect: maybeBind(host, host.useSourceOfProjectReferenceRedirect),
|
||||
getParsedCommandLine,
|
||||
|
||||
@ -284,6 +284,8 @@ namespace ts {
|
||||
/* @internal */ hasChangedAutomaticTypeDirectiveNames?: HasChangedAutomaticTypeDirectiveNames;
|
||||
/* @internal */ getGlobalTypingsCacheLocation?(): string | undefined;
|
||||
/* @internal */ getSymlinkCache?(files?: readonly SourceFile[]): SymlinkCache;
|
||||
/* Lets the Program from a AutoImportProviderProject use its host project's ModuleResolutionCache */
|
||||
/* @internal */ getModuleResolutionCache?(): ModuleResolutionCache | undefined;
|
||||
|
||||
/*
|
||||
* Required for full import and type reference completions.
|
||||
|
||||
@ -1907,6 +1907,7 @@ namespace ts {
|
||||
useCaseSensitiveFileNames: maybeBind(host, host.useCaseSensitiveFileNames),
|
||||
getSymlinkCache: maybeBind(host, host.getSymlinkCache) || program.getSymlinkCache,
|
||||
getModuleSpecifierCache: maybeBind(host, host.getModuleSpecifierCache),
|
||||
getPackageJsonInfoCache: () => program.getModuleResolutionCache()?.getPackageJsonInfoCache(),
|
||||
getGlobalTypingsCacheLocation: maybeBind(host, host.getGlobalTypingsCacheLocation),
|
||||
redirectTargetsMap: program.redirectTargetsMap,
|
||||
getProjectReferenceRedirect: fileName => program.getProjectReferenceRedirect(fileName),
|
||||
|
||||
@ -9874,6 +9874,7 @@ declare namespace ts.server {
|
||||
writeFile(fileName: string, content: string): void;
|
||||
fileExists(file: string): boolean;
|
||||
resolveModuleNames(moduleNames: string[], containingFile: string, reusedNames?: string[], redirectedReference?: ResolvedProjectReference, _options?: CompilerOptions, containingSourceFile?: SourceFile): (ResolvedModuleFull | undefined)[];
|
||||
getModuleResolutionCache(): ModuleResolutionCache | undefined;
|
||||
getResolvedModuleWithFailedLookupLocationsFromCache(moduleName: string, containingFile: string, resolutionMode?: ModuleKind.CommonJS | ModuleKind.ESNext): ResolvedModuleWithFailedLookupLocations | undefined;
|
||||
resolveTypeReferenceDirectives(typeDirectiveNames: string[], containingFile: string, redirectedReference?: ResolvedProjectReference): (ResolvedTypeReferenceDirective | undefined)[];
|
||||
directoryExists(path: string): boolean;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user