Optimize module resolution cache for watch and editor (#37055)

* Refactor resolveName

* Have resolutions of failed lookups as array and resolved to fileName map
This commit is contained in:
Sheetal Nandi 2020-03-11 14:35:26 -07:00 committed by GitHub
parent 6856c012d2
commit 1a9c8197ff
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 152 additions and 189 deletions

View File

@ -84,7 +84,11 @@ namespace ts {
return { fileName: resolved.path, packageId: resolved.packageId };
}
function createResolvedModuleWithFailedLookupLocations(resolved: Resolved | undefined, isExternalLibraryImport: boolean, failedLookupLocations: string[]): ResolvedModuleWithFailedLookupLocations {
function createResolvedModuleWithFailedLookupLocations(resolved: Resolved | undefined, isExternalLibraryImport: boolean | undefined, failedLookupLocations: string[], resultFromCache: ResolvedModuleWithFailedLookupLocations | undefined): ResolvedModuleWithFailedLookupLocations {
if (resultFromCache) {
resultFromCache.failedLookupLocations.push(...failedLookupLocations);
return resultFromCache;
}
return {
resolvedModule: resolved && { resolvedFileName: resolved.path, originalPath: resolved.originalPath === true ? undefined : resolved.originalPath, extension: resolved.extension, isExternalLibraryImport, packageId: resolved.packageId },
failedLookupLocations
@ -96,6 +100,7 @@ namespace ts {
compilerOptions: CompilerOptions;
traceEnabled: boolean;
failedLookupLocations: Push<string>;
resultFromCache?: ResolvedModuleWithFailedLookupLocations;
}
/** Just the fields that we use for module resolution. */
@ -926,11 +931,7 @@ namespace ts {
const state: ModuleResolutionState = { compilerOptions, host, traceEnabled, failedLookupLocations };
const result = forEach(extensions, ext => tryResolve(ext));
if (result && result.value) {
const { resolved, isExternalLibraryImport } = result.value;
return createResolvedModuleWithFailedLookupLocations(resolved, isExternalLibraryImport, failedLookupLocations);
}
return { resolvedModule: undefined, failedLookupLocations };
return createResolvedModuleWithFailedLookupLocations(result?.value?.resolved, result?.value?.isExternalLibraryImport, failedLookupLocations, state.resultFromCache);
function tryResolve(extensions: Extensions): SearchResult<{ resolved: Resolved, isExternalLibraryImport: boolean }> {
const loader: ResolutionKindSpecificLoader = (extensions, candidate, onlyRecordFailures, state) => nodeLoadModuleByRelativeName(extensions, candidate, onlyRecordFailures, state, /*considerPackageJson*/ true);
@ -1435,7 +1436,7 @@ namespace ts {
if (state.traceEnabled) {
trace(state.host, Diagnostics.Resolution_for_module_0_was_found_in_cache_from_location_1, moduleName, containingDirectory);
}
state.failedLookupLocations.push(...result.failedLookupLocations);
state.resultFromCache = result;
return { value: result.resolvedModule && { path: result.resolvedModule.resolvedFileName, originalPath: result.resolvedModule.originalPath || true, extension: result.resolvedModule.extension, packageId: result.resolvedModule.packageId } };
}
}
@ -1448,7 +1449,7 @@ namespace ts {
const resolved = tryResolve(Extensions.TypeScript) || tryResolve(Extensions.JavaScript);
// No originalPath because classic resolution doesn't resolve realPath
return createResolvedModuleWithFailedLookupLocations(resolved && resolved.value, /*isExternalLibraryImport*/ false, failedLookupLocations);
return createResolvedModuleWithFailedLookupLocations(resolved && resolved.value, /*isExternalLibraryImport*/ false, failedLookupLocations, state.resultFromCache);
function tryResolve(extensions: Extensions): SearchResult<Resolved> {
const resolvedUsingSettings = tryLoadModuleUsingOptionalResolutionSettings(extensions, moduleName, containingDirectory, loadModuleFromFileNoPackageId, state);
@ -1495,7 +1496,7 @@ namespace ts {
const failedLookupLocations: string[] = [];
const state: ModuleResolutionState = { compilerOptions, host, traceEnabled, failedLookupLocations };
const resolved = loadModuleFromImmediateNodeModulesDirectory(Extensions.DtsOnly, moduleName, globalCache, state, /*typesScopeOnly*/ false);
return createResolvedModuleWithFailedLookupLocations(resolved, /*isExternalLibraryImport*/ true, failedLookupLocations);
return createResolvedModuleWithFailedLookupLocations(resolved, /*isExternalLibraryImport*/ true, failedLookupLocations, state.resultFromCache);
}
/**

View File

@ -25,9 +25,11 @@ namespace ts {
}
interface ResolutionWithFailedLookupLocations {
readonly failedLookupLocations: readonly string[];
readonly failedLookupLocations: string[];
isInvalidated?: boolean;
refCount?: number;
// Files that have this resolution using
files?: Path[];
}
interface ResolutionWithResolvedFileName {
@ -53,7 +55,6 @@ namespace ts {
getGlobalCache?(): string | undefined;
globalCacheResolutionModuleName?(externalModuleName: string): string;
writeLog(s: string): void;
maxNumberOfFilesToIterateForInvalidation?: number;
getCurrentProgram(): Program | undefined;
fileIsOpen(filePath: Path): boolean;
}
@ -133,8 +134,6 @@ namespace ts {
return true;
}
export const maxNumberOfFilesToIterateForInvalidation = 256;
type GetResolutionWithResolvedFileName<T extends ResolutionWithFailedLookupLocations = ResolutionWithFailedLookupLocations, R extends ResolutionWithResolvedFileName = ResolutionWithResolvedFileName> =
(resolution: T) => R | undefined;
@ -142,9 +141,11 @@ namespace ts {
let filesWithChangedSetOfUnresolvedImports: Path[] | undefined;
let filesWithInvalidatedResolutions: Map<true> | undefined;
let filesWithInvalidatedNonRelativeUnresolvedImports: ReadonlyMap<readonly string[]> | undefined;
let allFilesHaveInvalidatedResolution = false;
const nonRelativeExternalModuleResolutions = createMultiMap<ResolutionWithFailedLookupLocations>();
const resolutionsWithFailedLookups: ResolutionWithFailedLookupLocations[] = [];
const resolvedFileToResolution = createMultiMap<ResolutionWithFailedLookupLocations>();
const getCurrentDirectory = memoize(() => resolutionHost.getCurrentDirectory!()); // TODO: GH#18217
const cachedDirectoryStructureHost = resolutionHost.getCachedDirectoryStructureHost();
@ -223,7 +224,8 @@ namespace ts {
closeTypeRootsWatch();
resolvedModuleNames.clear();
resolvedTypeReferenceDirectives.clear();
allFilesHaveInvalidatedResolution = false;
resolvedFileToResolution.clear();
resolutionsWithFailedLookups.length = 0;
// perDirectoryResolvedModuleNames and perDirectoryResolvedTypeReferenceDirectives could be non empty if there was exception during program update
// (between startCachingPerDirectoryResolution and finishCachingPerDirectoryResolution)
clearPerDirectoryResolutions();
@ -250,7 +252,7 @@ namespace ts {
}
function createHasInvalidatedResolution(forceAllFilesAsInvalidated?: boolean): HasInvalidatedResolution {
if (allFilesHaveInvalidatedResolution || forceAllFilesAsInvalidated) {
if (forceAllFilesAsInvalidated) {
// Any file asked would have invalidated resolution
filesWithInvalidatedResolutions = undefined;
return returnTrue;
@ -270,7 +272,6 @@ namespace ts {
}
function finishCachingPerDirectoryResolution() {
allFilesHaveInvalidatedResolution = false;
filesWithInvalidatedNonRelativeUnresolvedImports = undefined;
clearPerDirectoryResolutions();
directoryWatchesOfFailedLookups.forEach((watcher, path) => {
@ -300,7 +301,10 @@ namespace ts {
host,
globalCache);
if (resolvedModule) {
return { resolvedModule, failedLookupLocations: addRange(primaryResult.failedLookupLocations as string[], failedLookupLocations) };
// Modify existing resolution so its saved in the directory cache as well
(primaryResult.resolvedModule as any) = resolvedModule;
primaryResult.failedLookupLocations.push(...failedLookupLocations);
return primaryResult;
}
}
@ -308,18 +312,24 @@ namespace ts {
return primaryResult;
}
function resolveNamesWithLocalCache<T extends ResolutionWithFailedLookupLocations, R extends ResolutionWithResolvedFileName>(
names: readonly string[],
containingFile: string,
redirectedReference: ResolvedProjectReference | undefined,
cache: Map<Map<T>>,
perDirectoryCacheWithRedirects: CacheWithRedirects<Map<T>>,
loader: (name: string, containingFile: string, options: CompilerOptions, host: ModuleResolutionHost, redirectedReference?: ResolvedProjectReference) => T,
getResolutionWithResolvedFileName: GetResolutionWithResolvedFileName<T, R>,
shouldRetryResolution: (t: T) => boolean,
reusedNames: readonly string[] | undefined,
logChanges: boolean): (R | undefined)[] {
interface ResolveNamesWithLocalCacheInput<T extends ResolutionWithFailedLookupLocations, R extends ResolutionWithResolvedFileName> {
names: readonly string[];
containingFile: string;
redirectedReference: ResolvedProjectReference | undefined;
cache: Map<Map<T>>;
perDirectoryCacheWithRedirects: CacheWithRedirects<Map<T>>;
loader: (name: string, containingFile: string, options: CompilerOptions, host: ModuleResolutionHost, redirectedReference?: ResolvedProjectReference) => T;
getResolutionWithResolvedFileName: GetResolutionWithResolvedFileName<T, R>;
shouldRetryResolution: (t: T) => boolean;
reusedNames?: readonly string[];
logChanges?: boolean;
}
function resolveNamesWithLocalCache<T extends ResolutionWithFailedLookupLocations, R extends ResolutionWithResolvedFileName>({
names, containingFile, redirectedReference,
cache, perDirectoryCacheWithRedirects,
loader, getResolutionWithResolvedFileName,
shouldRetryResolution, reusedNames, logChanges
}: ResolveNamesWithLocalCacheInput<T, R>): (R | undefined)[] {
const path = resolutionHost.toPath(containingFile);
const resolutionsInFile = cache.get(path) || cache.set(path, createMap()).get(path)!;
const dirPath = getDirectoryPath(path);
@ -345,7 +355,7 @@ namespace ts {
let resolution = resolutionsInFile.get(name);
// Resolution is valid if it is present and not invalidated
if (!seenNamesInFile.has(name) &&
allFilesHaveInvalidatedResolution || unmatchedRedirects || !resolution || resolution.isInvalidated ||
unmatchedRedirects || !resolution || resolution.isInvalidated ||
// If the name is unresolved import that was invalidated, recalculate
(hasInvalidatedNonRelativeUnresolvedImport && !isExternalModuleNameRelative(name) && shouldRetryResolution(resolution))) {
const existingResolution = resolution;
@ -358,9 +368,9 @@ namespace ts {
perDirectoryResolution.set(name, resolution);
}
resolutionsInFile.set(name, resolution);
watchFailedLookupLocationsOfExternalModuleResolutions(name, resolution);
watchFailedLookupLocationsOfExternalModuleResolutions(name, resolution, path, getResolutionWithResolvedFileName);
if (existingResolution) {
stopWatchFailedLookupLocationOfResolution(existingResolution);
stopWatchFailedLookupLocationOfResolution(existingResolution, path, getResolutionWithResolvedFileName);
}
if (logChanges && filesWithChangedSetOfUnresolvedImports && !resolutionIsEqualTo(existingResolution, resolution)) {
@ -377,7 +387,7 @@ namespace ts {
// Stop watching and remove the unused name
resolutionsInFile.forEach((resolution, name) => {
if (!seenNamesInFile.has(name) && !contains(reusedNames, name)) {
stopWatchFailedLookupLocationOfResolution(resolution);
stopWatchFailedLookupLocationOfResolution(resolution, path, getResolutionWithResolvedFileName);
resolutionsInFile.delete(name);
}
});
@ -404,23 +414,31 @@ namespace ts {
}
function resolveTypeReferenceDirectives(typeDirectiveNames: string[], containingFile: string, redirectedReference?: ResolvedProjectReference): (ResolvedTypeReferenceDirective | undefined)[] {
return resolveNamesWithLocalCache<CachedResolvedTypeReferenceDirectiveWithFailedLookupLocations, ResolvedTypeReferenceDirective>(
typeDirectiveNames, containingFile, redirectedReference,
resolvedTypeReferenceDirectives, perDirectoryResolvedTypeReferenceDirectives,
resolveTypeReferenceDirective, getResolvedTypeReferenceDirective,
/*shouldRetryResolution*/ resolution => resolution.resolvedTypeReferenceDirective === undefined,
/*reusedNames*/ undefined, /*logChanges*/ false
);
return resolveNamesWithLocalCache<CachedResolvedTypeReferenceDirectiveWithFailedLookupLocations, ResolvedTypeReferenceDirective>({
names: typeDirectiveNames,
containingFile,
redirectedReference,
cache: resolvedTypeReferenceDirectives,
perDirectoryCacheWithRedirects: perDirectoryResolvedTypeReferenceDirectives,
loader: resolveTypeReferenceDirective,
getResolutionWithResolvedFileName: getResolvedTypeReferenceDirective,
shouldRetryResolution: resolution => resolution.resolvedTypeReferenceDirective === undefined,
});
}
function resolveModuleNames(moduleNames: string[], containingFile: string, reusedNames: string[] | undefined, redirectedReference?: ResolvedProjectReference): (ResolvedModuleFull | undefined)[] {
return resolveNamesWithLocalCache<CachedResolvedModuleWithFailedLookupLocations, ResolvedModuleFull>(
moduleNames, containingFile, redirectedReference,
resolvedModuleNames, perDirectoryResolvedModuleNames,
resolveModuleName, getResolvedModule,
/*shouldRetryResolution*/ resolution => !resolution.resolvedModule || !resolutionExtensionIsTSOrJson(resolution.resolvedModule.extension),
reusedNames, logChangesWhenResolvingModule
);
return resolveNamesWithLocalCache<CachedResolvedModuleWithFailedLookupLocations, ResolvedModuleFull>({
names: moduleNames,
containingFile,
redirectedReference,
cache: resolvedModuleNames,
perDirectoryCacheWithRedirects: perDirectoryResolvedModuleNames,
loader: resolveModuleName,
getResolutionWithResolvedFileName: getResolvedModule,
shouldRetryResolution: resolution => !resolution.resolvedModule || !resolutionExtensionIsTSOrJson(resolution.resolvedModule.extension),
reusedNames,
logChanges: logChangesWhenResolvingModule
});
}
function getResolvedModuleWithFailedLookupLocationsFromCache(moduleName: string, containingFile: string): CachedResolvedModuleWithFailedLookupLocations | undefined {
@ -498,28 +516,40 @@ namespace ts {
return fileExtensionIsOneOf(path, failedLookupDefaultExtensions);
}
function watchFailedLookupLocationsOfExternalModuleResolutions(name: string, resolution: ResolutionWithFailedLookupLocations) {
// No need to set the resolution refCount
if (resolution.failedLookupLocations && resolution.failedLookupLocations.length) {
if (resolution.refCount) {
resolution.refCount++;
function watchFailedLookupLocationsOfExternalModuleResolutions<T extends ResolutionWithFailedLookupLocations, R extends ResolutionWithResolvedFileName>(
name: string,
resolution: T,
filePath: Path,
getResolutionWithResolvedFileName: GetResolutionWithResolvedFileName<T, R>,
) {
if (resolution.refCount) {
resolution.refCount++;
Debug.assertDefined(resolution.files);
}
else {
resolution.refCount = 1;
Debug.assert(resolution.files === undefined);
if (isExternalModuleNameRelative(name)) {
watchFailedLookupLocationOfResolution(resolution);
}
else {
resolution.refCount = 1;
if (isExternalModuleNameRelative(name)) {
watchFailedLookupLocationOfResolution(resolution);
}
else {
nonRelativeExternalModuleResolutions.add(name, resolution);
}
nonRelativeExternalModuleResolutions.add(name, resolution);
}
const resolved = getResolutionWithResolvedFileName(resolution);
if (resolved && resolved.resolvedFileName) {
resolvedFileToResolution.add(resolutionHost.toPath(resolved.resolvedFileName), resolution);
}
}
(resolution.files || (resolution.files = [])).push(filePath);
}
function watchFailedLookupLocationOfResolution(resolution: ResolutionWithFailedLookupLocations) {
Debug.assert(!!resolution.refCount);
const { failedLookupLocations } = resolution;
if (!failedLookupLocations.length) return;
resolutionsWithFailedLookups.push(resolution);
let setAtRoot = false;
for (const failedLookupLocation of failedLookupLocations) {
const failedLookupLocationPath = resolutionHost.toPath(failedLookupLocation);
@ -548,15 +578,11 @@ namespace ts {
}
}
function setRefCountToUndefined(resolution: ResolutionWithFailedLookupLocations) {
resolution.refCount = undefined;
}
function watchFailedLookupLocationOfNonRelativeModuleResolutions(resolutions: ResolutionWithFailedLookupLocations[], name: string) {
const program = resolutionHost.getCurrentProgram();
const updateResolution = program && program.getTypeChecker().tryFindAmbientModuleWithoutAugmentations(name) ?
setRefCountToUndefined : watchFailedLookupLocationOfResolution;
resolutions.forEach(updateResolution);
if (!program || !program.getTypeChecker().tryFindAmbientModuleWithoutAugmentations(name)) {
resolutions.forEach(watchFailedLookupLocationOfResolution);
}
}
function setDirectoryWatcher(dir: string, dirPath: Path, nonRecursive?: boolean) {
@ -570,13 +596,23 @@ namespace ts {
}
}
function stopWatchFailedLookupLocationOfResolution(resolution: ResolutionWithFailedLookupLocations) {
if (!resolution.refCount) {
function stopWatchFailedLookupLocationOfResolution<T extends ResolutionWithFailedLookupLocations, R extends ResolutionWithResolvedFileName>(
resolution: T,
filePath: Path,
getResolutionWithResolvedFileName: GetResolutionWithResolvedFileName<T, R>,
) {
unorderedRemoveItem(Debug.assertDefined(resolution.files), filePath);
resolution.refCount!--;
if (resolution.refCount) {
return;
}
const resolved = getResolutionWithResolvedFileName(resolution);
if (resolved && resolved.resolvedFileName) {
resolvedFileToResolution.remove(resolutionHost.toPath(resolved.resolvedFileName), resolution);
}
resolution.refCount--;
if (resolution.refCount) {
if (!unorderedRemoveItem(resolutionsWithFailedLookups, resolution)) {
// If not watching failed lookups, it wont be there in resolutionsWithFailedLookups
return;
}
@ -625,17 +661,21 @@ namespace ts {
cachedDirectoryStructureHost.addOrDeleteFileOrDirectory(fileOrDirectory, fileOrDirectoryPath);
}
if (!allFilesHaveInvalidatedResolution && invalidateResolutionOfFailedLookupLocation(fileOrDirectoryPath, dirPath === fileOrDirectoryPath)) {
if (invalidateResolutionOfFailedLookupLocation(fileOrDirectoryPath, dirPath === fileOrDirectoryPath)) {
resolutionHost.onInvalidatedResolution();
}
}, nonRecursive ? WatchDirectoryFlags.None : WatchDirectoryFlags.Recursive);
}
function removeResolutionsOfFileFromCache(cache: Map<Map<ResolutionWithFailedLookupLocations>>, filePath: Path) {
function removeResolutionsOfFileFromCache<T extends ResolutionWithFailedLookupLocations, R extends ResolutionWithResolvedFileName>(
cache: Map<Map<T>>,
filePath: Path,
getResolutionWithResolvedFileName: GetResolutionWithResolvedFileName<T, R>,
) {
// Deleted file, stop watching failed lookups for all the resolutions in the file
const resolutions = cache.get(filePath);
if (resolutions) {
resolutions.forEach(stopWatchFailedLookupLocationOfResolution);
resolutions.forEach(resolution => stopWatchFailedLookupLocationOfResolution(resolution, filePath, getResolutionWithResolvedFileName));
cache.delete(filePath);
}
}
@ -655,69 +695,27 @@ namespace ts {
}
function removeResolutionsOfFile(filePath: Path) {
removeResolutionsOfFileFromCache(resolvedModuleNames, filePath);
removeResolutionsOfFileFromCache(resolvedTypeReferenceDirectives, filePath);
removeResolutionsOfFileFromCache(resolvedModuleNames, filePath, getResolvedModule);
removeResolutionsOfFileFromCache(resolvedTypeReferenceDirectives, filePath, getResolvedTypeReferenceDirective);
}
function invalidateResolutionCache<T extends ResolutionWithFailedLookupLocations, R extends ResolutionWithResolvedFileName>(
cache: Map<Map<T>>,
isInvalidatedResolution: (resolution: T, getResolutionWithResolvedFileName: GetResolutionWithResolvedFileName<T, R>) => boolean,
getResolutionWithResolvedFileName: GetResolutionWithResolvedFileName<T, R>
) {
const seen = createMap<Map<true>>();
cache.forEach((resolutions, containingFilePath) => {
const dirPath = getDirectoryPath(containingFilePath);
let seenInDir = seen.get(dirPath);
if (!seenInDir) {
seenInDir = createMap<true>();
seen.set(dirPath, seenInDir);
}
resolutions.forEach((resolution, name) => {
if (seenInDir!.has(name)) {
return;
}
seenInDir!.set(name, true);
if (!resolution.isInvalidated && isInvalidatedResolution(resolution, getResolutionWithResolvedFileName)) {
// Mark the file as needing re-evaluation of module resolution instead of using it blindly.
resolution.isInvalidated = true;
(filesWithInvalidatedResolutions || (filesWithInvalidatedResolutions = createMap<true>())).set(containingFilePath, true);
// When its a file with inferred types resolution, invalidate type reference directive resolution
if (endsWith(containingFilePath, inferredTypesContainingFile)) {
resolutionHost.onChangedAutomaticTypeDirectiveNames();
}
}
});
});
}
function hasReachedResolutionIterationLimit() {
const maxSize = resolutionHost.maxNumberOfFilesToIterateForInvalidation || maxNumberOfFilesToIterateForInvalidation;
return resolvedModuleNames.size > maxSize || resolvedTypeReferenceDirectives.size > maxSize;
}
function invalidateResolutions(
isInvalidatedResolution: (resolution: ResolutionWithFailedLookupLocations, getResolutionWithResolvedFileName: GetResolutionWithResolvedFileName) => boolean,
) {
// If more than maxNumberOfFilesToIterateForInvalidation present,
// just invalidated all files and recalculate the resolutions for files instead
if (hasReachedResolutionIterationLimit()) {
allFilesHaveInvalidatedResolution = true;
return;
function invalidateResolution(resolution: ResolutionWithFailedLookupLocations) {
resolution.isInvalidated = true;
let changedInAutoTypeReferenced = false;
for (const containingFilePath of Debug.assertDefined(resolution.files)) {
(filesWithInvalidatedResolutions || (filesWithInvalidatedResolutions = createMap<true>())).set(containingFilePath, true);
// When its a file with inferred types resolution, invalidate type reference directive resolution
changedInAutoTypeReferenced = changedInAutoTypeReferenced || containingFilePath.endsWith(inferredTypesContainingFile);
}
if (changedInAutoTypeReferenced) {
resolutionHost.onChangedAutomaticTypeDirectiveNames();
}
invalidateResolutionCache(resolvedModuleNames, isInvalidatedResolution, getResolvedModule);
invalidateResolutionCache(resolvedTypeReferenceDirectives, isInvalidatedResolution, getResolvedTypeReferenceDirective);
}
function invalidateResolutionOfFile(filePath: Path) {
removeResolutionsOfFile(filePath);
invalidateResolutions(
// Resolution is invalidated if the resulting file name is same as the deleted file path
(resolution, getResolutionWithResolvedFileName) => {
const result = getResolutionWithResolvedFileName(resolution);
return !!result && resolutionHost.toPath(result.resolvedFileName!) === filePath; // TODO: GH#18217
}
);
// Resolution is invalidated if the resulting file name is same as the deleted file path
forEach(resolvedFileToResolution.get(filePath), invalidateResolution);
}
function setFilesWithInvalidatedNonRelativeUnresolvedImports(filesMap: ReadonlyMap<readonly string[]>) {
@ -766,13 +764,15 @@ namespace ts {
isChangedFailedLookupLocation = location => resolutionHost.toPath(location) === fileOrDirectoryPath;
}
}
const hasChangedFailedLookupLocation = (resolution: ResolutionWithFailedLookupLocations) => some(resolution.failedLookupLocations, isChangedFailedLookupLocation);
const invalidatedFilesCount = filesWithInvalidatedResolutions && filesWithInvalidatedResolutions.size;
invalidateResolutions(
// Resolution is invalidated if the resulting file name is same as the deleted file path
hasChangedFailedLookupLocation
);
return allFilesHaveInvalidatedResolution || filesWithInvalidatedResolutions && filesWithInvalidatedResolutions.size !== invalidatedFilesCount;
let invalidated = false;
// Resolution is invalidated if the resulting file name is same as the deleted file path
for (const resolution of resolutionsWithFailedLookups) {
if (resolution.failedLookupLocations.some(isChangedFailedLookupLocation)) {
invalidateResolution(resolution);
invalidated = true;
}
}
return invalidated;
}
function closeTypeRootsWatch() {
@ -780,10 +780,6 @@ namespace ts {
}
function getDirectoryToWatchFailedLookupLocationFromTypeRoot(typeRoot: string, typeRootPath: Path): Path | undefined {
if (allFilesHaveInvalidatedResolution) {
return undefined;
}
if (isInDirectoryPath(rootPath, typeRootPath)) {
return rootPath;
}

View File

@ -5648,7 +5648,7 @@ namespace ts {
export interface ResolvedModuleWithFailedLookupLocations {
readonly resolvedModule: ResolvedModuleFull | undefined;
/* @internal */
readonly failedLookupLocations: readonly string[];
readonly failedLookupLocations: string[];
}
export interface ResolvedTypeReferenceDirective {
@ -5663,7 +5663,7 @@ namespace ts {
export interface ResolvedTypeReferenceDirectiveWithFailedLookupLocations {
readonly resolvedTypeReferenceDirective: ResolvedTypeReferenceDirective | undefined;
readonly failedLookupLocations: readonly string[];
readonly failedLookupLocations: string[];
}
/* @internal */

View File

@ -116,10 +116,6 @@ namespace ts {
export interface WatchCompilerHost<T extends BuilderProgram> extends ProgramHost<T>, WatchHost {
/** If provided, callback to invoke after every new program creation */
afterProgramCreate?(program: T): void;
// Only for testing
/*@internal*/
maxNumberOfFilesToIterateForInvalidation?: number;
}
/**
@ -293,7 +289,6 @@ namespace ts {
scheduleProgramUpdate();
};
compilerHost.fileIsOpen = returnFalse;
compilerHost.maxNumberOfFilesToIterateForInvalidation = host.maxNumberOfFilesToIterateForInvalidation;
compilerHost.getCurrentProgram = getCurrentProgram;
compilerHost.writeLog = writeLog;

View File

@ -156,7 +156,6 @@ namespace ts {
sys: System,
cb: ExecuteCommandLineCallbacks,
commandLine: ParsedCommandLine,
maxNumberOfFilesToIterateForInvalidation: number | undefined
) {
let reportDiagnostic = createDiagnosticReporter(sys);
if (commandLine.options.build) {
@ -271,7 +270,6 @@ namespace ts {
configParseResult,
commandLineOptions,
commandLine.watchOptions,
maxNumberOfFilesToIterateForInvalidation
);
}
else if (isIncrementalCompilation(configParseResult.options)) {
@ -311,7 +309,6 @@ namespace ts {
commandLine.fileNames,
commandLineOptions,
commandLine.watchOptions,
maxNumberOfFilesToIterateForInvalidation
);
}
else if (isIncrementalCompilation(commandLineOptions)) {
@ -346,7 +343,6 @@ namespace ts {
system: System,
cb: ExecuteCommandLineCallbacks,
commandLineArgs: readonly string[],
maxNumberOfFilesToIterateForInvalidation?: number
) {
if (isBuild(commandLineArgs)) {
const { buildOptions, watchOptions, projects, errors } = parseBuildCommand(commandLineArgs.slice(1));
@ -378,11 +374,10 @@ namespace ts {
system,
cb,
commandLine,
maxNumberOfFilesToIterateForInvalidation
));
}
else {
return executeCommandLineWorker(system, cb, commandLine, maxNumberOfFilesToIterateForInvalidation);
return executeCommandLineWorker(system, cb, commandLine);
}
}
@ -556,10 +551,8 @@ namespace ts {
sys: System,
cb: ExecuteCommandLineCallbacks,
watchCompilerHost: WatchCompilerHost<EmitAndSemanticDiagnosticsBuilderProgram>,
maxNumberOfFilesToIterateForInvalidation: number | undefined
) {
updateCreateProgram(sys, watchCompilerHost);
watchCompilerHost.maxNumberOfFilesToIterateForInvalidation = maxNumberOfFilesToIterateForInvalidation;
const emitFilesUsingBuilder = watchCompilerHost.afterProgramCreate!; // TODO: GH#18217
watchCompilerHost.afterProgramCreate = builderProgram => {
emitFilesUsingBuilder(builderProgram);
@ -579,7 +572,6 @@ namespace ts {
configParseResult: ParsedCommandLine,
optionsToExtend: CompilerOptions,
watchOptionsToExtend: WatchOptions | undefined,
maxNumberOfFilesToIterateForInvalidation: number | undefined
) {
const watchCompilerHost = createWatchCompilerHostOfConfigFile(
configParseResult.options.configFilePath!,
@ -590,7 +582,7 @@ namespace ts {
reportDiagnostic,
createWatchStatusReporter(sys, configParseResult.options)
); // TODO: GH#18217
updateWatchCompilationHost(sys, cb, watchCompilerHost, maxNumberOfFilesToIterateForInvalidation);
updateWatchCompilationHost(sys, cb, watchCompilerHost);
watchCompilerHost.configFileParsingResult = configParseResult;
return createWatchProgram(watchCompilerHost);
}
@ -602,7 +594,6 @@ namespace ts {
rootFiles: string[],
options: CompilerOptions,
watchOptions: WatchOptions | undefined,
maxNumberOfFilesToIterateForInvalidation: number | undefined
) {
const watchCompilerHost = createWatchCompilerHostOfFilesAndCompilerOptions(
rootFiles,
@ -613,7 +604,7 @@ namespace ts {
reportDiagnostic,
createWatchStatusReporter(sys, options)
);
updateWatchCompilationHost(sys, cb, watchCompilerHost, maxNumberOfFilesToIterateForInvalidation);
updateWatchCompilationHost(sys, cb, watchCompilerHost);
return createWatchProgram(watchCompilerHost);
}

View File

@ -33,15 +33,13 @@ namespace ts.tscWatch {
export type Watch = WatchOfConfigFile<EmitAndSemanticDiagnosticsBuilderProgram> | WatchOfFilesAndCompilerOptions<EmitAndSemanticDiagnosticsBuilderProgram>;
export function createWatchOfConfigFile(configFileName: string, host: WatchedSystem, optionsToExtend?: CompilerOptions, watchOptionsToExtend?: WatchOptions, maxNumberOfFilesToIterateForInvalidation?: number) {
export function createWatchOfConfigFile(configFileName: string, host: WatchedSystem, optionsToExtend?: CompilerOptions, watchOptionsToExtend?: WatchOptions) {
const compilerHost = createWatchCompilerHostOfConfigFile(configFileName, optionsToExtend || {}, watchOptionsToExtend, host);
compilerHost.maxNumberOfFilesToIterateForInvalidation = maxNumberOfFilesToIterateForInvalidation;
return createWatchProgram(compilerHost);
}
export function createWatchOfFilesAndCompilerOptions(rootFiles: string[], host: WatchedSystem, options: CompilerOptions = {}, watchOptions?: WatchOptions, maxNumberOfFilesToIterateForInvalidation?: number) {
export function createWatchOfFilesAndCompilerOptions(rootFiles: string[], host: WatchedSystem, options: CompilerOptions = {}, watchOptions?: WatchOptions) {
const compilerHost = createWatchCompilerHostOfFilesAndCompilerOptions(rootFiles, options, watchOptions, host);
compilerHost.maxNumberOfFilesToIterateForInvalidation = maxNumberOfFilesToIterateForInvalidation;
return createWatchProgram(compilerHost);
}
@ -288,7 +286,6 @@ namespace ts.tscWatch {
}
export interface TscWatchCompile extends TscWatchCompileBase {
sys: () => WatchedSystem;
maxNumberOfFilesToIterateForInvalidation?: number;
}
export type SystemSnap = ReturnType<WatchedSystem["snap"]>;
@ -308,7 +305,6 @@ namespace ts.tscWatch {
sys,
cb,
commandLineArgs,
input.maxNumberOfFilesToIterateForInvalidation
);
runWatchBaseline({
scenario,

View File

@ -984,7 +984,6 @@ declare const eval: any`
scenario,
subScenario: `should not trigger recompilation because of program emit/${subScenario}`,
commandLineArgs: ["-w", "-p", `${projectRoot}/tsconfig.json`],
maxNumberOfFilesToIterateForInvalidation: 1,
sys: () => {
const file1: File = {
path: `${projectRoot}/file1.ts`,

View File

@ -320,7 +320,6 @@ declare module "fs" {
scenario,
subScenario: `ignores changes in node_modules that start with dot/${subScenario}`,
commandLineArgs,
maxNumberOfFilesToIterateForInvalidation: 1,
sys: () => {
const file1: File = {
path: `${projectRoot}/test.ts`,

View File

@ -418,7 +418,7 @@ namespace ts.projectSystem {
});
describe("resolution when resolution cache size", () => {
function verifyWithMaxCacheLimit(limitHit: boolean, useSlashRootAsSomeNotRootFolderInUserDirectory: boolean) {
function verifyWithMaxCacheLimit(useSlashRootAsSomeNotRootFolderInUserDirectory: boolean) {
const rootFolder = useSlashRootAsSomeNotRootFolderInUserDirectory ? "/user/username/rootfolder/otherfolder/" : "/";
const file1: File = {
path: rootFolder + "a/b/project/file1.ts",
@ -451,9 +451,6 @@ namespace ts.projectSystem {
checkNumberOfProjects(projectService, { configuredProjects: 1 });
const project = projectService.configuredProjects.get(configFile.path)!;
verifyProject();
if (limitHit) {
(project as ResolutionCacheHost).maxNumberOfFilesToIterateForInvalidation = 1;
}
file3.content += "export class d {}";
host.reloadFS(projectFiles);
@ -495,20 +492,12 @@ namespace ts.projectSystem {
}
}
it("limit not hit and project is not at root level", () => {
verifyWithMaxCacheLimit(/*limitHit*/ false, /*useSlashRootAsSomeNotRootFolderInUserDirectory*/ true);
it("project is not at root level", () => {
verifyWithMaxCacheLimit(/*useSlashRootAsSomeNotRootFolderInUserDirectory*/ true);
});
it("limit hit and project is not at root level", () => {
verifyWithMaxCacheLimit(/*limitHit*/ true, /*useSlashRootAsSomeNotRootFolderInUserDirectory*/ true);
});
it("limit not hit and project is at root level", () => {
verifyWithMaxCacheLimit(/*limitHit*/ false, /*useSlashRootAsSomeNotRootFolderInUserDirectory*/ false);
});
it("limit hit and project is at root level", () => {
verifyWithMaxCacheLimit(/*limitHit*/ true, /*useSlashRootAsSomeNotRootFolderInUserDirectory*/ false);
it("project is at root level", () => {
verifyWithMaxCacheLimit(/*useSlashRootAsSomeNotRootFolderInUserDirectory*/ false);
});
});
}

View File

@ -902,7 +902,6 @@ export const x = 10;`
checkNumberOfProjects(service, { inferredProjects: 1 });
const project = service.inferredProjects[0];
checkProjectActualFiles(project, files.map(f => f.path));
(project as ResolutionCacheHost).maxNumberOfFilesToIterateForInvalidation = 1;
host.checkTimeoutQueueLength(0);
host.ensureFileOrFolder(npmCacheFile);
@ -943,8 +942,6 @@ export const x = 10;`
const resolutionTrace = createHostModuleResolutionTrace(host);
const service = createProjectService(host);
service.openClientFile(file1.path);
const project = service.configuredProjects.get(configFile.path)!;
(project as ResolutionCacheHost).maxNumberOfFilesToIterateForInvalidation = 1;
const expectedTrace = getExpectedNonRelativeModuleResolutionTrace(host, file1, module1, module1Name);
getExpectedNonRelativeModuleResolutionTrace(host, file1, module2, module2Name, expectedTrace);
verifyTrace(resolutionTrace, expectedTrace);

View File

@ -2918,7 +2918,7 @@ declare namespace ts {
}
export interface ResolvedTypeReferenceDirectiveWithFailedLookupLocations {
readonly resolvedTypeReferenceDirective: ResolvedTypeReferenceDirective | undefined;
readonly failedLookupLocations: readonly string[];
readonly failedLookupLocations: string[];
}
export interface CompilerHost extends ModuleResolutionHost {
getSourceFile(fileName: string, languageVersion: ScriptTarget, onError?: (message: string) => void, shouldCreateNewSourceFile?: boolean): SourceFile | undefined;

View File

@ -2918,7 +2918,7 @@ declare namespace ts {
}
export interface ResolvedTypeReferenceDirectiveWithFailedLookupLocations {
readonly resolvedTypeReferenceDirective: ResolvedTypeReferenceDirective | undefined;
readonly failedLookupLocations: readonly string[];
readonly failedLookupLocations: string[];
}
export interface CompilerHost extends ModuleResolutionHost {
getSourceFile(fileName: string, languageVersion: ScriptTarget, onError?: (message: string) => void, shouldCreateNewSourceFile?: boolean): SourceFile | undefined;