Use non relative name cache for type reference resolutions and API updates (#51732)

* Make the non relative name resolution cache generic

* Add cache for non relative type reference resolution

* Add getter only methods so we can use these in future for sharing resolutions across the projects

* Mark existing non relative module name cache getOrCreate as deprecated

* Prefer getters for getting directory results
This commit is contained in:
Sheetal Nandi 2022-12-06 14:22:03 -08:00 committed by GitHub
parent 703652cebf
commit 38f33ade06
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 200 additions and 91 deletions

View File

@ -447,8 +447,11 @@ export function resolveTypeReferenceDirective(typeReferenceDirectiveName: string
}
const containingDirectory = containingFile ? getDirectoryPath(containingFile) : undefined;
const perFolderCache = containingDirectory ? cache && cache.getOrCreateCacheForDirectory(containingDirectory, redirectedReference) : undefined;
let result = perFolderCache && perFolderCache.get(typeReferenceDirectiveName, /*mode*/ resolutionMode);
let result = containingDirectory ? cache?.getFromDirectoryCache(typeReferenceDirectiveName, resolutionMode, containingDirectory, redirectedReference) : undefined;
if (!result && containingDirectory && !isExternalModuleNameRelative(typeReferenceDirectiveName)) {
result = cache?.getFromNonRelativeNameCache(typeReferenceDirectiveName, resolutionMode, containingDirectory, redirectedReference);
}
if (result) {
if (traceEnabled) {
trace(host, Diagnostics.Resolving_type_reference_directive_0_containing_file_1, typeReferenceDirectiveName, containingFile);
@ -459,6 +462,7 @@ export function resolveTypeReferenceDirective(typeReferenceDirectiveName: string
return result;
}
const typeRoots = getEffectiveTypeRoots(options, host);
if (traceEnabled) {
if (containingFile === undefined) {
@ -537,7 +541,12 @@ export function resolveTypeReferenceDirective(typeReferenceDirectiveName: string
affectingLocations: initializeResolutionField(affectingLocations),
resolutionDiagnostics: initializeResolutionField(diagnostics),
};
perFolderCache?.set(typeReferenceDirectiveName, /*mode*/ resolutionMode, result);
if (containingDirectory) {
cache?.getOrCreateCacheForDirectory(containingDirectory, redirectedReference).set(typeReferenceDirectiveName, /*mode*/ resolutionMode, result);
if (!isExternalModuleNameRelative(typeReferenceDirectiveName)) {
cache?.getOrCreateCacheForNonRelativeName(typeReferenceDirectiveName, resolutionMode, redirectedReference).set(containingDirectory, result);
}
}
if (traceEnabled) traceResult(result);
return result;
@ -678,7 +687,7 @@ export function getAutomaticTypeDirectiveNames(options: CompilerOptions, host: M
return result;
}
export interface TypeReferenceDirectiveResolutionCache extends PerDirectoryResolutionCache<ResolvedTypeReferenceDirectiveWithFailedLookupLocations>, PackageJsonInfoCache {
export interface TypeReferenceDirectiveResolutionCache extends PerDirectoryResolutionCache<ResolvedTypeReferenceDirectiveWithFailedLookupLocations>, NonRelativeNameResolutionCache<ResolvedTypeReferenceDirectiveWithFailedLookupLocations>, PackageJsonInfoCache {
/** @internal */ clearAllExceptPackageJsonInfoCache(): void;
}
@ -696,6 +705,7 @@ export interface ModeAwareCache<T> {
* This assumes that any module id will have the same resolution for sibling files located in the same folder.
*/
export interface PerDirectoryResolutionCache<T> {
getFromDirectoryCache(name: string, mode: ResolutionMode, directoryName: string, redirectedReference: ResolvedProjectReference | undefined): T | undefined;
getOrCreateCacheForDirectory(directoryName: string, redirectedReference?: ResolvedProjectReference): ModeAwareCache<T>;
clear(): void;
/**
@ -705,6 +715,22 @@ export interface PerDirectoryResolutionCache<T> {
update(options: CompilerOptions): void;
}
export interface NonRelativeNameResolutionCache<T> {
getFromNonRelativeNameCache(nonRelativeName: string, mode: ResolutionMode, directoryName: string, redirectedReference: ResolvedProjectReference | undefined): T | undefined;
getOrCreateCacheForNonRelativeName(nonRelativeName: string, mode: ResolutionMode, redirectedReference?: ResolvedProjectReference): PerNonRelativeNameCache<T>;
clear(): void;
/**
* Updates with the current compilerOptions the cache will operate with.
* This updates the redirects map as well if needed so module resolutions are cached if they can across the projects
*/
update(options: CompilerOptions): void;
}
export interface PerNonRelativeNameCache<T> {
get(directory: string): T | undefined;
set(directory: string, result: T): void;
}
export interface ModuleResolutionCache extends PerDirectoryResolutionCache<ResolvedModuleWithFailedLookupLocations>, NonRelativeModuleNameResolutionCache, PackageJsonInfoCache {
getPackageJsonInfoCache(): PackageJsonInfoCache;
/** @internal */ clearAllExceptPackageJsonInfoCache(): void;
@ -714,7 +740,8 @@ export interface ModuleResolutionCache extends PerDirectoryResolutionCache<Resol
* Stored map from non-relative module name to a table: directory -> result of module lookup in this directory
* We support only non-relative module names because resolution of relative module names is usually more deterministic and thus less expensive.
*/
export interface NonRelativeModuleNameResolutionCache extends PackageJsonInfoCache {
export interface NonRelativeModuleNameResolutionCache extends NonRelativeNameResolutionCache<ResolvedModuleWithFailedLookupLocations>, PackageJsonInfoCache {
/** @deprecated Use getOrCreateCacheForNonRelativeName */
getOrCreateCacheForModuleName(nonRelativeModuleName: string, mode: ResolutionMode, redirectedReference?: ResolvedProjectReference): PerModuleNameCache;
}
@ -726,10 +753,7 @@ export interface PackageJsonInfoCache {
clear(): void;
}
export interface PerModuleNameCache {
get(directory: string): ResolvedModuleWithFailedLookupLocations | undefined;
set(directory: string, result: ResolvedModuleWithFailedLookupLocations): void;
}
export type PerModuleNameCache = PerNonRelativeNameCache<ResolvedModuleWithFailedLookupLocations>;
function compilerOptionValueToString(value: unknown): string {
if (value === null || typeof value !== "object") { // eslint-disable-line no-null/no-null
@ -754,6 +778,7 @@ export function getKeyForCompilerOptions(options: CompilerOptions, affectingOpti
/** @internal */
export interface CacheWithRedirects<K, V> {
getMapOfCacheRedirects(redirectedReference: ResolvedProjectReference | undefined): Map<K, V> | undefined;
getOrCreateMapOfCacheRedirects(redirectedReference: ResolvedProjectReference | undefined): Map<K, V>;
update(newOptions: CompilerOptions): void;
clear(): void;
@ -768,26 +793,35 @@ export function createCacheWithRedirects<K, V>(ownOptions: CompilerOptions | und
let ownMap = new Map<K, V>();
if (ownOptions) redirectsMap.set(ownOptions, ownMap);
return {
getMapOfCacheRedirects,
getOrCreateMapOfCacheRedirects,
update,
clear,
};
function getMapOfCacheRedirects(redirectedReference: ResolvedProjectReference | undefined): Map<K, V> | undefined {
return redirectedReference ?
getOrCreateMap(redirectedReference.commandLine.options, /*create*/ false) :
ownMap;
}
function getOrCreateMapOfCacheRedirects(redirectedReference: ResolvedProjectReference | undefined): Map<K, V> {
return redirectedReference ?
getOrCreateMap(redirectedReference.commandLine.options) :
getOrCreateMap(redirectedReference.commandLine.options, /*create*/ true) :
ownMap;
}
function update(newOptions: CompilerOptions) {
if (ownOptions !== newOptions) {
if (ownOptions) ownMap = getOrCreateMap(newOptions); // set new map for new options as ownMap
if (ownOptions) ownMap = getOrCreateMap(newOptions, /*create*/ true); // set new map for new options as ownMap
else redirectsMap.set(newOptions, ownMap); // Use existing map if oldOptions = undefined
ownOptions = newOptions;
}
}
function getOrCreateMap(redirectOptions: CompilerOptions): Map<K, V> {
function getOrCreateMap(redirectOptions: CompilerOptions, create: true): Map<K, V>;
function getOrCreateMap(redirectOptions: CompilerOptions, create: false): Map<K, V> | undefined;
function getOrCreateMap(redirectOptions: CompilerOptions, create: boolean): Map<K, V> | undefined {
let result = redirectsMap.get(redirectOptions);
if (result) return result;
const key = getRedirectsCacheKey(redirectOptions);
@ -798,9 +832,10 @@ export function createCacheWithRedirects<K, V>(ownOptions: CompilerOptions | und
if (ownKey === key) result = ownMap;
else if (!redirectsKeyToMap.has(ownKey)) redirectsKeyToMap.set(ownKey, ownMap);
}
redirectsKeyToMap.set(key, result ??= new Map());
if (create) result ??= new Map();
if (result) redirectsKeyToMap.set(key, result);
}
redirectsMap.set(redirectOptions, result);
if (result) redirectsMap.set(redirectOptions, result);
return result;
}
@ -856,8 +891,10 @@ function getOrCreateCache<K, V>(cacheWithRedirects: CacheWithRedirects<K, V>, re
return result;
}
function createPerDirectoryResolutionCache<T>(currentDirectory: string, getCanonicalFileName: GetCanonicalFileName, directoryToModuleNameMap: CacheWithRedirects<Path, ModeAwareCache<T>>): PerDirectoryResolutionCache<T> {
function createPerDirectoryResolutionCache<T>(currentDirectory: string, getCanonicalFileName: GetCanonicalFileName, options: CompilerOptions | undefined): PerDirectoryResolutionCache<T> {
const directoryToModuleNameMap = createCacheWithRedirects<Path, ModeAwareCache<T>>(options);
return {
getFromDirectoryCache,
getOrCreateCacheForDirectory,
clear,
update,
@ -875,6 +912,11 @@ function createPerDirectoryResolutionCache<T>(currentDirectory: string, getCanon
const path = toPath(directoryName, currentDirectory, getCanonicalFileName);
return getOrCreateCache(directoryToModuleNameMap, redirectedReference, path, () => createModeAwareCache());
}
function getFromDirectoryCache(name: string, mode: ResolutionMode, directoryName: string, redirectedReference: ResolvedProjectReference | undefined) {
const path = toPath(directoryName, currentDirectory, getCanonicalFileName);
return directoryToModuleNameMap.getMapOfCacheRedirects(redirectedReference)?.get(path)?.get(name, mode);
}
}
/** @internal */
@ -938,52 +980,53 @@ export function zipToModeAwareCache<K, V>(
return map;
}
export function createModuleResolutionCache(
function getOriginalOrResolvedModuleFileName(result: ResolvedModuleWithFailedLookupLocations) {
return result.resolvedModule && (result.resolvedModule.originalPath || result.resolvedModule.resolvedFileName);
}
function getOriginalOrResolvedTypeReferenceFileName(result: ResolvedTypeReferenceDirectiveWithFailedLookupLocations) {
return result.resolvedTypeReferenceDirective &&
(result.resolvedTypeReferenceDirective.originalPath || result.resolvedTypeReferenceDirective.resolvedFileName);
}
function createNonRelativeNameResolutionCache<T>(
currentDirectory: string,
getCanonicalFileName: (s: string) => string,
options?: CompilerOptions
): ModuleResolutionCache {
const directoryToModuleNameMap = createCacheWithRedirects<Path, ModeAwareCache<ResolvedModuleWithFailedLookupLocations>>(options);
const perDirectoryResolutionCache = createPerDirectoryResolutionCache(currentDirectory, getCanonicalFileName, directoryToModuleNameMap);
const moduleNameToDirectoryMap = createCacheWithRedirects<ModeAwareCacheKey, PerModuleNameCache>(options);
const packageJsonInfoCache = createPackageJsonInfoCache(currentDirectory, getCanonicalFileName);
options: CompilerOptions | undefined,
getResolvedFileName: (result: T) => string | undefined,
): NonRelativeNameResolutionCache<T> {
const moduleNameToDirectoryMap = createCacheWithRedirects<ModeAwareCacheKey, PerNonRelativeNameCache<T>>(options);
return {
...packageJsonInfoCache,
...perDirectoryResolutionCache,
getOrCreateCacheForModuleName,
getFromNonRelativeNameCache,
getOrCreateCacheForNonRelativeName,
clear,
update,
getPackageJsonInfoCache: () => packageJsonInfoCache,
clearAllExceptPackageJsonInfoCache,
};
function clear() {
clearAllExceptPackageJsonInfoCache();
packageJsonInfoCache.clear();
}
function clearAllExceptPackageJsonInfoCache() {
perDirectoryResolutionCache.clear();
moduleNameToDirectoryMap.clear();
}
function update(options: CompilerOptions) {
directoryToModuleNameMap.update(options);
moduleNameToDirectoryMap.update(options);
}
function getOrCreateCacheForModuleName(nonRelativeModuleName: string, mode: ResolutionMode, redirectedReference?: ResolvedProjectReference): PerModuleNameCache {
function getFromNonRelativeNameCache(nonRelativeModuleName: string, mode: ResolutionMode, directoryName: string, redirectedReference?: ResolvedProjectReference): T | undefined {
Debug.assert(!isExternalModuleNameRelative(nonRelativeModuleName));
return moduleNameToDirectoryMap.getMapOfCacheRedirects(redirectedReference)?.get(createModeAwareCacheKey(nonRelativeModuleName, mode))?.get(directoryName);
}
function getOrCreateCacheForNonRelativeName(nonRelativeModuleName: string, mode: ResolutionMode, redirectedReference?: ResolvedProjectReference): PerNonRelativeNameCache<T> {
Debug.assert(!isExternalModuleNameRelative(nonRelativeModuleName));
return getOrCreateCache(moduleNameToDirectoryMap, redirectedReference, createModeAwareCacheKey(nonRelativeModuleName, mode), createPerModuleNameCache);
}
function createPerModuleNameCache(): PerModuleNameCache {
const directoryPathMap = new Map<Path, ResolvedModuleWithFailedLookupLocations>();
function createPerModuleNameCache(): PerNonRelativeNameCache<T> {
const directoryPathMap = new Map<Path, T>();
return { get, set };
function get(directory: string): ResolvedModuleWithFailedLookupLocations | undefined {
function get(directory: string): T | undefined {
return directoryPathMap.get(toPath(directory, currentDirectory, getCanonicalFileName));
}
@ -998,7 +1041,7 @@ export function createModuleResolutionCache(
* ]
* this means that request for module resolution from file in any of these folder will be immediately found in cache.
*/
function set(directory: string, result: ResolvedModuleWithFailedLookupLocations): void {
function set(directory: string, result: T): void {
const path = toPath(directory, currentDirectory, getCanonicalFileName);
// if entry is already in cache do nothing
if (directoryPathMap.has(path)) {
@ -1006,8 +1049,7 @@ export function createModuleResolutionCache(
}
directoryPathMap.set(path, result);
const resolvedFileName = result.resolvedModule &&
(result.resolvedModule.originalPath || result.resolvedModule.resolvedFileName);
const resolvedFileName = getResolvedFileName(result);
// find common prefix between directory and resolved file name
// this common prefix should be the shortest path that has the same resolution
// directory: /a/b/c/d/e
@ -1051,20 +1093,33 @@ export function createModuleResolutionCache(
}
}
export function createTypeReferenceDirectiveResolutionCache(
interface ModuleOrTypeReferenceResolutionCache<T> extends PerDirectoryResolutionCache<T>, NonRelativeNameResolutionCache<T>, PackageJsonInfoCache {
getPackageJsonInfoCache(): PackageJsonInfoCache;
clearAllExceptPackageJsonInfoCache(): void;
}
function createModuleOrTypeReferenceResolutionCache<T>(
currentDirectory: string,
getCanonicalFileName: (s: string) => string,
options?: CompilerOptions,
packageJsonInfoCache?: PackageJsonInfoCache,
): TypeReferenceDirectiveResolutionCache {
const directoryToModuleNameMap = createCacheWithRedirects<Path, ModeAwareCache<ResolvedTypeReferenceDirectiveWithFailedLookupLocations>>(options);
const perDirectoryResolutionCache = createPerDirectoryResolutionCache(currentDirectory, getCanonicalFileName, directoryToModuleNameMap);
packageJsonInfoCache ||= createPackageJsonInfoCache(currentDirectory, getCanonicalFileName);
options: CompilerOptions | undefined,
packageJsonInfoCache: PackageJsonInfoCache | undefined,
getResolvedFileName: (result: T) => string | undefined,
): ModuleOrTypeReferenceResolutionCache<T> {
const perDirectoryResolutionCache = createPerDirectoryResolutionCache<T>(currentDirectory, getCanonicalFileName, options);
const nonRelativeNameResolutionCache = createNonRelativeNameResolutionCache(
currentDirectory,
getCanonicalFileName,
options,
getResolvedFileName,
);
packageJsonInfoCache ??= createPackageJsonInfoCache(currentDirectory, getCanonicalFileName);
return {
...packageJsonInfoCache,
...perDirectoryResolutionCache,
...nonRelativeNameResolutionCache,
clear,
update,
getPackageJsonInfoCache: () => packageJsonInfoCache!,
clearAllExceptPackageJsonInfoCache,
};
@ -1075,14 +1130,49 @@ export function createTypeReferenceDirectiveResolutionCache(
function clearAllExceptPackageJsonInfoCache() {
perDirectoryResolutionCache.clear();
nonRelativeNameResolutionCache.clear();
}
function update(options: CompilerOptions) {
perDirectoryResolutionCache.update(options);
nonRelativeNameResolutionCache.update(options);
}
}
export function createModuleResolutionCache(
currentDirectory: string,
getCanonicalFileName: (s: string) => string,
options?: CompilerOptions
): ModuleResolutionCache {
const result = createModuleOrTypeReferenceResolutionCache(
currentDirectory,
getCanonicalFileName,
options,
/*packageJsonInfoCache*/ undefined,
getOriginalOrResolvedModuleFileName,
) as ModuleResolutionCache;
result.getOrCreateCacheForModuleName = (nonRelativeName, mode, redirectedReference) => result.getOrCreateCacheForNonRelativeName(nonRelativeName, mode, redirectedReference);
return result;
}
export function createTypeReferenceDirectiveResolutionCache(
currentDirectory: string,
getCanonicalFileName: (s: string) => string,
options?: CompilerOptions,
packageJsonInfoCache?: PackageJsonInfoCache,
): TypeReferenceDirectiveResolutionCache {
return createModuleOrTypeReferenceResolutionCache(
currentDirectory,
getCanonicalFileName,
options,
packageJsonInfoCache,
getOriginalOrResolvedTypeReferenceFileName
);
}
export function resolveModuleNameFromCache(moduleName: string, containingFile: string, cache: ModuleResolutionCache, mode?: ResolutionMode): ResolvedModuleWithFailedLookupLocations | undefined {
const containingDirectory = getDirectoryPath(containingFile);
const perFolderCache = cache && cache.getOrCreateCacheForDirectory(containingDirectory);
if (!perFolderCache) return undefined;
return perFolderCache.get(moduleName, mode);
return cache.getFromDirectoryCache(moduleName, mode, containingDirectory, /*redirectedReference*/ undefined);
}
export function resolveModuleName(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost, cache?: ModuleResolutionCache, redirectedReference?: ResolvedProjectReference, resolutionMode?: ResolutionMode): ResolvedModuleWithFailedLookupLocations {
@ -1097,8 +1187,7 @@ export function resolveModuleName(moduleName: string, containingFile: string, co
}
}
const containingDirectory = getDirectoryPath(containingFile);
const perFolderCache = cache && cache.getOrCreateCacheForDirectory(containingDirectory, redirectedReference);
let result = perFolderCache && perFolderCache.get(moduleName, resolutionMode);
let result = cache?.getFromDirectoryCache(moduleName, resolutionMode, containingDirectory, redirectedReference);
if (result) {
if (traceEnabled) {
@ -1152,12 +1241,10 @@ export function resolveModuleName(moduleName: string, containingFile: string, co
if (result && result.resolvedModule) perfLogger.logInfoEvent(`Module "${moduleName}" resolved to "${result.resolvedModule.resolvedFileName}"`);
perfLogger.logStopResolveModule((result && result.resolvedModule) ? "" + result.resolvedModule.resolvedFileName : "null");
if (perFolderCache) {
perFolderCache.set(moduleName, resolutionMode, result);
if (!isExternalModuleNameRelative(moduleName)) {
// put result in per-module name cache
cache.getOrCreateCacheForModuleName(moduleName, resolutionMode, redirectedReference).set(containingDirectory, result);
}
cache?.getOrCreateCacheForDirectory(containingDirectory, redirectedReference).set(moduleName, resolutionMode, result);
if (!isExternalModuleNameRelative(moduleName)) {
// put result in per-module name cache
cache?.getOrCreateCacheForNonRelativeName(moduleName, resolutionMode, redirectedReference).set(containingDirectory, result);
}
}
@ -2512,7 +2599,7 @@ function loadModuleFromNearestNodeModulesDirectoryTypesScope(moduleName: string,
}
function loadModuleFromNearestNodeModulesDirectoryWorker(extensions: Extensions, moduleName: string, directory: string, state: ModuleResolutionState, typesScopeOnly: boolean, cache: ModuleResolutionCache | undefined, redirectedReference: ResolvedProjectReference | undefined): SearchResult<Resolved> {
const perModuleNameCache = cache && cache.getOrCreateCacheForModuleName(moduleName, state.features === 0 ? undefined : state.features & NodeResolutionFeatures.EsmMode ? ModuleKind.ESNext : ModuleKind.CommonJS, redirectedReference);
const mode = state.features === 0 ? undefined : state.features & NodeResolutionFeatures.EsmMode ? ModuleKind.ESNext : ModuleKind.CommonJS;
// Do (up to) two passes through node_modules:
// 1. For each ancestor node_modules directory, try to find:
// i. TS/DTS files in the implementation package
@ -2534,7 +2621,7 @@ function loadModuleFromNearestNodeModulesDirectoryWorker(extensions: Extensions,
function lookup(extensions: Extensions) {
return forEachAncestorDirectory(normalizeSlashes(directory), ancestorDirectory => {
if (getBaseFileName(ancestorDirectory) !== "node_modules") {
const resolutionFromCache = tryFindNonRelativeModuleNameInCache(perModuleNameCache, moduleName, ancestorDirectory, state);
const resolutionFromCache = tryFindNonRelativeModuleNameInCache(cache, moduleName, mode, ancestorDirectory, redirectedReference, state);
if (resolutionFromCache) {
return resolutionFromCache;
}
@ -2719,8 +2806,8 @@ export function unmangleScopedPackageName(typesPackageName: string): string {
typesPackageName;
}
function tryFindNonRelativeModuleNameInCache(cache: PerModuleNameCache | undefined, moduleName: string, containingDirectory: string, state: ModuleResolutionState): SearchResult<Resolved> {
const result = cache && cache.get(containingDirectory);
function tryFindNonRelativeModuleNameInCache(cache: NonRelativeModuleNameResolutionCache | undefined, moduleName: string, mode: ResolutionMode, containingDirectory: string, redirectedReference: ResolvedProjectReference | undefined, state: ModuleResolutionState): SearchResult<Resolved> {
const result = cache && cache.getFromNonRelativeNameCache(moduleName, mode, containingDirectory, redirectedReference);
if (result) {
if (state.traceEnabled) {
trace(state.host, Diagnostics.Resolution_for_module_0_was_found_in_cache_from_location_1, moduleName, containingDirectory);
@ -2769,10 +2856,9 @@ export function classicNameResolver(moduleName: string, containingFile: string,
}
if (!isExternalModuleNameRelative(moduleName)) {
const perModuleNameCache = cache && cache.getOrCreateCacheForModuleName(moduleName, /*mode*/ undefined, redirectedReference);
// Climb up parent directories looking for a module.
const resolved = forEachAncestorDirectory(containingDirectory, directory => {
const resolutionFromCache = tryFindNonRelativeModuleNameInCache(perModuleNameCache, moduleName, directory, state);
const resolutionFromCache = tryFindNonRelativeModuleNameInCache(cache, moduleName, /*mode*/ undefined, directory, redirectedReference, state);
if (resolutionFromCache) {
return resolutionFromCache;
}

View File

@ -1855,7 +1855,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
// This may totally change if/when the issue of output paths not mapping to input files is fixed in a broader context
// When it is, how we extract diagnostics from the module name resolver will have the be refined - the current cache
// APIs wrapping the underlying resolver make it almost impossible to smuggle the diagnostics out in a generalized way
const fromCache = moduleResolutionCache.getOrCreateCacheForModuleName(name, mode, redirectedReference).get(containingDir);
const fromCache = moduleResolutionCache.getFromNonRelativeNameCache(name, mode, containingDir, redirectedReference);
if (fromCache) addResolutionDiagnostics(fromCache);
}

View File

@ -162,7 +162,7 @@ describe("unittests:: moduleResolution:: Node module resolution - relative paths
describe("unittests:: moduleResolution:: Node module resolution - non-relative paths", () => {
it("computes correct commonPrefix for moduleName cache", () => {
const resolutionCache = ts.createModuleResolutionCache("/", (f) => f);
let cache = resolutionCache.getOrCreateCacheForModuleName("a", /*mode*/ undefined);
let cache = resolutionCache.getOrCreateCacheForNonRelativeName("a", /*mode*/ undefined);
cache.set("/sub", {
resolvedModule: {
originalPath: undefined,
@ -177,7 +177,7 @@ describe("unittests:: moduleResolution:: Node module resolution - non-relative p
assert.isDefined(cache.get("/sub"));
assert.isUndefined(cache.get("/"));
cache = resolutionCache.getOrCreateCacheForModuleName("b", /*mode*/ undefined);
cache = resolutionCache.getOrCreateCacheForNonRelativeName("b", /*mode*/ undefined);
cache.set("/sub/dir/foo", {
resolvedModule: {
originalPath: undefined,
@ -194,7 +194,7 @@ describe("unittests:: moduleResolution:: Node module resolution - non-relative p
assert.isDefined(cache.get("/sub"));
assert.isUndefined(cache.get("/"));
cache = resolutionCache.getOrCreateCacheForModuleName("c", /*mode*/ undefined);
cache = resolutionCache.getOrCreateCacheForNonRelativeName("c", /*mode*/ undefined);
cache.set("/foo/bar", {
resolvedModule: {
originalPath: undefined,
@ -210,7 +210,7 @@ describe("unittests:: moduleResolution:: Node module resolution - non-relative p
assert.isDefined(cache.get("/foo"));
assert.isDefined(cache.get("/"));
cache = resolutionCache.getOrCreateCacheForModuleName("d", /*mode*/ undefined);
cache = resolutionCache.getOrCreateCacheForNonRelativeName("d", /*mode*/ undefined);
cache.set("/foo", {
resolvedModule: {
originalPath: undefined,
@ -225,7 +225,7 @@ describe("unittests:: moduleResolution:: Node module resolution - non-relative p
assert.isDefined(cache.get("/foo"));
assert.isUndefined(cache.get("/"));
cache = resolutionCache.getOrCreateCacheForModuleName("e", /*mode*/ undefined);
cache = resolutionCache.getOrCreateCacheForNonRelativeName("e", /*mode*/ undefined);
cache.set("c:/foo", {
resolvedModule: {
originalPath: undefined,
@ -241,7 +241,7 @@ describe("unittests:: moduleResolution:: Node module resolution - non-relative p
assert.isDefined(cache.get("c:/"));
assert.isUndefined(cache.get("d:/"));
cache = resolutionCache.getOrCreateCacheForModuleName("f", /*mode*/ undefined);
cache = resolutionCache.getOrCreateCacheForNonRelativeName("f", /*mode*/ undefined);
cache.set("/foo/bar/baz", {
resolvedModule: undefined,
failedLookupLocations: [],

View File

@ -42,7 +42,7 @@ describe("unittests:: tsserver:: getEditsForFileRename", () => {
readFile: path => host.readFile(path),
fileExists: path => host.fileExists(path),
resolveModuleNames: (moduleNames, containingFile) => moduleNames.map(name => ts.resolveModuleName(name, containingFile, options, lsHost, moduleResolutionCache).resolvedModule),
getResolvedModuleWithFailedLookupLocationsFromCache: (moduleName, containingFile, mode) => moduleResolutionCache.getOrCreateCacheForDirectory(ts.getDirectoryPath(containingFile)).get(moduleName, mode),
getResolvedModuleWithFailedLookupLocationsFromCache: (moduleName, containingFile, mode) => moduleResolutionCache.getFromDirectoryCache(moduleName, mode, ts.getDirectoryPath(containingFile), /*redirectedReference*/ undefined),
};
const service = ts.createLanguageService(lsHost);
const edits = service.getEditsForFileRename("/old.ts", "/new.ts", ts.testFormatSettings, ts.emptyOptions);

View File

@ -9187,7 +9187,7 @@ declare namespace ts {
function resolveModuleName(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost, cache?: ModuleResolutionCache, redirectedReference?: ResolvedProjectReference, resolutionMode?: ResolutionMode): ResolvedModuleWithFailedLookupLocations;
function nodeModuleNameResolver(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost, cache?: ModuleResolutionCache, redirectedReference?: ResolvedProjectReference): ResolvedModuleWithFailedLookupLocations;
function classicNameResolver(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost, cache?: NonRelativeModuleNameResolutionCache, redirectedReference?: ResolvedProjectReference): ResolvedModuleWithFailedLookupLocations;
interface TypeReferenceDirectiveResolutionCache extends PerDirectoryResolutionCache<ResolvedTypeReferenceDirectiveWithFailedLookupLocations>, PackageJsonInfoCache {
interface TypeReferenceDirectiveResolutionCache extends PerDirectoryResolutionCache<ResolvedTypeReferenceDirectiveWithFailedLookupLocations>, NonRelativeNameResolutionCache<ResolvedTypeReferenceDirectiveWithFailedLookupLocations>, PackageJsonInfoCache {
}
interface ModeAwareCache<T> {
get(key: string, mode: ResolutionMode): T | undefined;
@ -9202,6 +9202,7 @@ declare namespace ts {
* This assumes that any module id will have the same resolution for sibling files located in the same folder.
*/
interface PerDirectoryResolutionCache<T> {
getFromDirectoryCache(name: string, mode: ResolutionMode, directoryName: string, redirectedReference: ResolvedProjectReference | undefined): T | undefined;
getOrCreateCacheForDirectory(directoryName: string, redirectedReference?: ResolvedProjectReference): ModeAwareCache<T>;
clear(): void;
/**
@ -9210,6 +9211,20 @@ declare namespace ts {
*/
update(options: CompilerOptions): void;
}
interface NonRelativeNameResolutionCache<T> {
getFromNonRelativeNameCache(nonRelativeName: string, mode: ResolutionMode, directoryName: string, redirectedReference: ResolvedProjectReference | undefined): T | undefined;
getOrCreateCacheForNonRelativeName(nonRelativeName: string, mode: ResolutionMode, redirectedReference?: ResolvedProjectReference): PerNonRelativeNameCache<T>;
clear(): void;
/**
* Updates with the current compilerOptions the cache will operate with.
* This updates the redirects map as well if needed so module resolutions are cached if they can across the projects
*/
update(options: CompilerOptions): void;
}
interface PerNonRelativeNameCache<T> {
get(directory: string): T | undefined;
set(directory: string, result: T): void;
}
interface ModuleResolutionCache extends PerDirectoryResolutionCache<ResolvedModuleWithFailedLookupLocations>, NonRelativeModuleNameResolutionCache, PackageJsonInfoCache {
getPackageJsonInfoCache(): PackageJsonInfoCache;
}
@ -9217,16 +9232,14 @@ declare namespace ts {
* Stored map from non-relative module name to a table: directory -> result of module lookup in this directory
* We support only non-relative module names because resolution of relative module names is usually more deterministic and thus less expensive.
*/
interface NonRelativeModuleNameResolutionCache extends PackageJsonInfoCache {
interface NonRelativeModuleNameResolutionCache extends NonRelativeNameResolutionCache<ResolvedModuleWithFailedLookupLocations>, PackageJsonInfoCache {
/** @deprecated Use getOrCreateCacheForNonRelativeName */
getOrCreateCacheForModuleName(nonRelativeModuleName: string, mode: ResolutionMode, redirectedReference?: ResolvedProjectReference): PerModuleNameCache;
}
interface PackageJsonInfoCache {
clear(): void;
}
interface PerModuleNameCache {
get(directory: string): ResolvedModuleWithFailedLookupLocations | undefined;
set(directory: string, result: ResolvedModuleWithFailedLookupLocations): void;
}
type PerModuleNameCache = PerNonRelativeNameCache<ResolvedModuleWithFailedLookupLocations>;
/**
* Visits a Node using the supplied visitor, possibly returning a new Node in its place.
*

View File

@ -5254,7 +5254,7 @@ declare namespace ts {
function resolveModuleName(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost, cache?: ModuleResolutionCache, redirectedReference?: ResolvedProjectReference, resolutionMode?: ResolutionMode): ResolvedModuleWithFailedLookupLocations;
function nodeModuleNameResolver(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost, cache?: ModuleResolutionCache, redirectedReference?: ResolvedProjectReference): ResolvedModuleWithFailedLookupLocations;
function classicNameResolver(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost, cache?: NonRelativeModuleNameResolutionCache, redirectedReference?: ResolvedProjectReference): ResolvedModuleWithFailedLookupLocations;
interface TypeReferenceDirectiveResolutionCache extends PerDirectoryResolutionCache<ResolvedTypeReferenceDirectiveWithFailedLookupLocations>, PackageJsonInfoCache {
interface TypeReferenceDirectiveResolutionCache extends PerDirectoryResolutionCache<ResolvedTypeReferenceDirectiveWithFailedLookupLocations>, NonRelativeNameResolutionCache<ResolvedTypeReferenceDirectiveWithFailedLookupLocations>, PackageJsonInfoCache {
}
interface ModeAwareCache<T> {
get(key: string, mode: ResolutionMode): T | undefined;
@ -5269,6 +5269,7 @@ declare namespace ts {
* This assumes that any module id will have the same resolution for sibling files located in the same folder.
*/
interface PerDirectoryResolutionCache<T> {
getFromDirectoryCache(name: string, mode: ResolutionMode, directoryName: string, redirectedReference: ResolvedProjectReference | undefined): T | undefined;
getOrCreateCacheForDirectory(directoryName: string, redirectedReference?: ResolvedProjectReference): ModeAwareCache<T>;
clear(): void;
/**
@ -5277,6 +5278,20 @@ declare namespace ts {
*/
update(options: CompilerOptions): void;
}
interface NonRelativeNameResolutionCache<T> {
getFromNonRelativeNameCache(nonRelativeName: string, mode: ResolutionMode, directoryName: string, redirectedReference: ResolvedProjectReference | undefined): T | undefined;
getOrCreateCacheForNonRelativeName(nonRelativeName: string, mode: ResolutionMode, redirectedReference?: ResolvedProjectReference): PerNonRelativeNameCache<T>;
clear(): void;
/**
* Updates with the current compilerOptions the cache will operate with.
* This updates the redirects map as well if needed so module resolutions are cached if they can across the projects
*/
update(options: CompilerOptions): void;
}
interface PerNonRelativeNameCache<T> {
get(directory: string): T | undefined;
set(directory: string, result: T): void;
}
interface ModuleResolutionCache extends PerDirectoryResolutionCache<ResolvedModuleWithFailedLookupLocations>, NonRelativeModuleNameResolutionCache, PackageJsonInfoCache {
getPackageJsonInfoCache(): PackageJsonInfoCache;
}
@ -5284,16 +5299,14 @@ declare namespace ts {
* Stored map from non-relative module name to a table: directory -> result of module lookup in this directory
* We support only non-relative module names because resolution of relative module names is usually more deterministic and thus less expensive.
*/
interface NonRelativeModuleNameResolutionCache extends PackageJsonInfoCache {
interface NonRelativeModuleNameResolutionCache extends NonRelativeNameResolutionCache<ResolvedModuleWithFailedLookupLocations>, PackageJsonInfoCache {
/** @deprecated Use getOrCreateCacheForNonRelativeName */
getOrCreateCacheForModuleName(nonRelativeModuleName: string, mode: ResolutionMode, redirectedReference?: ResolvedProjectReference): PerModuleNameCache;
}
interface PackageJsonInfoCache {
clear(): void;
}
interface PerModuleNameCache {
get(directory: string): ResolvedModuleWithFailedLookupLocations | undefined;
set(directory: string, result: ResolvedModuleWithFailedLookupLocations): void;
}
type PerModuleNameCache = PerNonRelativeNameCache<ResolvedModuleWithFailedLookupLocations>;
/**
* Visits a Node using the supplied visitor, possibly returning a new Node in its place.
*

View File

@ -5,10 +5,7 @@
"File '/node_modules/@types/alpha/index.d.ts' exist - use it as a name resolution result.",
"Resolving real path for '/node_modules/@types/alpha/index.d.ts', result '/node_modules/@types/alpha/index.d.ts'.",
"======== Type reference directive 'alpha' was successfully resolved to '/node_modules/@types/alpha/index.d.ts', primary: true. ========",
"======== Resolving type reference directive 'alpha', containing file '/__inferred type names__.ts', root directory '/node_modules/@types'. ========",
"Resolving with primary search path '/node_modules/@types'.",
"File '/node_modules/@types/alpha/package.json' does not exist according to earlier cached lookups.",
"File '/node_modules/@types/alpha/index.d.ts' exist - use it as a name resolution result.",
"Resolving real path for '/node_modules/@types/alpha/index.d.ts', result '/node_modules/@types/alpha/index.d.ts'.",
"======== Resolving type reference directive 'alpha', containing file '/__inferred type names__.ts'. ========",
"Resolution for type reference directive 'alpha' was found in cache from location '/'.",
"======== Type reference directive 'alpha' was successfully resolved to '/node_modules/@types/alpha/index.d.ts', primary: true. ========"
]