From f432ce4105e2830e62ea4b32df0249ce85edd603 Mon Sep 17 00:00:00 2001 From: Andy Hanson Date: Tue, 23 Oct 2018 17:15:21 -0700 Subject: [PATCH 1/2] Miscellaneous code cleanup relating to module resolution --- src/compiler/resolutionCache.ts | 8 +-- src/harness/virtualFileSystemWithWatch.ts | 8 +-- src/server/project.ts | 66 ++++++++--------------- 3 files changed, 30 insertions(+), 52 deletions(-) diff --git a/src/compiler/resolutionCache.ts b/src/compiler/resolutionCache.ts index b11de69b0e296..4f01bc8d7516d 100644 --- a/src/compiler/resolutionCache.ts +++ b/src/compiler/resolutionCache.ts @@ -80,7 +80,7 @@ namespace ts { export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootDirForResolution: string | undefined, logChangesWhenResolvingModule: boolean): ResolutionCache { let filesWithChangedSetOfUnresolvedImports: Path[] | undefined; let filesWithInvalidatedResolutions: Map | undefined; - let filesWithInvalidatedNonRelativeUnresolvedImports: Map> | undefined; + let filesWithInvalidatedNonRelativeUnresolvedImports: ReadonlyMap> | undefined; let allFilesHaveInvalidatedResolution = false; const nonRelativeExternalModuleResolutions = createMultiMap(); @@ -242,14 +242,14 @@ namespace ts { } function resolveNamesWithLocalCache( - names: string[], + names: ReadonlyArray, containingFile: string, redirectedReference: ResolvedProjectReference | undefined, cache: Map>, perDirectoryCacheWithRedirects: CacheWithRedirects>, loader: (name: string, containingFile: string, options: CompilerOptions, host: ModuleResolutionHost, redirectedReference?: ResolvedProjectReference) => T, getResolutionWithResolvedFileName: GetResolutionWithResolvedFileName, - reusedNames: string[] | undefined, + reusedNames: ReadonlyArray | undefined, logChanges: boolean): (R | undefined)[] { const path = resolutionHost.toPath(containingFile); @@ -681,7 +681,7 @@ namespace ts { ); } - function setFilesWithInvalidatedNonRelativeUnresolvedImports(filesMap: Map>) { + function setFilesWithInvalidatedNonRelativeUnresolvedImports(filesMap: ReadonlyMap>) { Debug.assert(filesWithInvalidatedNonRelativeUnresolvedImports === filesMap || filesWithInvalidatedNonRelativeUnresolvedImports === undefined); filesWithInvalidatedNonRelativeUnresolvedImports = filesMap; } diff --git a/src/harness/virtualFileSystemWithWatch.ts b/src/harness/virtualFileSystemWithWatch.ts index d2b7c7869c568..bd31a04a0df13 100644 --- a/src/harness/virtualFileSystemWithWatch.ts +++ b/src/harness/virtualFileSystemWithWatch.ts @@ -128,7 +128,7 @@ interface Array {}` return s && isString((s).symLink); } - function invokeWatcherCallbacks(callbacks: T[], invokeCallback: (cb: T) => void): void { + function invokeWatcherCallbacks(callbacks: ReadonlyArray | undefined, invokeCallback: (cb: T) => void): void { if (callbacks) { // The array copy is made to ensure that even if one of the callback removes the callbacks, // we dont miss any callbacks following it @@ -650,15 +650,15 @@ interface Array {}` // For overriding the methods invokeWatchedDirectoriesCallback(folderFullPath: string, relativePath: string) { - invokeWatcherCallbacks(this.watchedDirectories.get(this.toPath(folderFullPath))!, cb => this.directoryCallback(cb, relativePath)); + invokeWatcherCallbacks(this.watchedDirectories.get(this.toPath(folderFullPath)), cb => this.directoryCallback(cb, relativePath)); } invokeWatchedDirectoriesRecursiveCallback(folderFullPath: string, relativePath: string) { - invokeWatcherCallbacks(this.watchedDirectoriesRecursive.get(this.toPath(folderFullPath))!, cb => this.directoryCallback(cb, relativePath)); + invokeWatcherCallbacks(this.watchedDirectoriesRecursive.get(this.toPath(folderFullPath)), cb => this.directoryCallback(cb, relativePath)); } private invokeFileWatcher(fileFullPath: string, eventKind: FileWatcherEventKind, useFileNameInCallback?: boolean) { - invokeWatcherCallbacks(this.watchedFiles.get(this.toPath(fileFullPath))!, ({ cb, fileName }) => cb(useFileNameInCallback ? fileName : fileFullPath, eventKind)); + invokeWatcherCallbacks(this.watchedFiles.get(this.toPath(fileFullPath)), ({ cb, fileName }) => cb(useFileNameInCallback ? fileName : fileFullPath, eventKind)); } private getRelativePathToDirectory(directoryFullPath: string, fileFullPath: string) { diff --git a/src/server/project.ts b/src/server/project.ts index b87ddc9fb7f34..61e867cb83522 100644 --- a/src/server/project.ts +++ b/src/server/project.ts @@ -789,41 +789,6 @@ namespace ts.server { } } - /* @internal */ - private extractUnresolvedImportsFromSourceFile(file: SourceFile, ambientModules: string[]): ReadonlyArray { - const cached = this.cachedUnresolvedImportsPerFile.get(file.path); - if (cached) { - // found cached result, return - return cached; - } - let unresolvedImports: string[] | undefined; - if (file.resolvedModules) { - file.resolvedModules.forEach((resolvedModule, name) => { - // pick unresolved non-relative names - if (!resolvedModule && !isExternalModuleNameRelative(name) && !isAmbientlyDeclaredModule(name)) { - // for non-scoped names extract part up-to the first slash - // for scoped names - extract up to the second slash - let trimmed = name.trim(); - let i = trimmed.indexOf("/"); - if (i !== -1 && trimmed.charCodeAt(0) === CharacterCodes.at) { - i = trimmed.indexOf("/", i + 1); - } - if (i !== -1) { - trimmed = trimmed.substr(0, i); - } - (unresolvedImports || (unresolvedImports = [])).push(trimmed); - } - }); - } - - this.cachedUnresolvedImportsPerFile.set(file.path, unresolvedImports || emptyArray); - return unresolvedImports || emptyArray; - - function isAmbientlyDeclaredModule(name: string) { - return ambientModules.some(m => m === name); - } - } - /* @internal */ onFileAddedOrRemoved() { this.hasAddedorRemovedFiles = true; @@ -857,15 +822,7 @@ namespace ts.server { // (can reuse cached imports for files that were not changed) // 4. compilation settings were changed in the way that might affect module resolution - drop all caches and collect all data from the scratch if (hasNewProgram || changedFiles.length) { - let result: string[] | undefined; - const ambientModules = this.program.getTypeChecker().getAmbientModules().map(mod => stripQuotes(mod.getName())); - for (const sourceFile of this.program.getSourceFiles()) { - const unResolved = this.extractUnresolvedImportsFromSourceFile(sourceFile, ambientModules); - if (unResolved !== emptyArray) { - (result || (result = [])).push(...unResolved); - } - } - this.lastCachedUnresolvedImportsList = result ? toDeduplicatedSortedArray(result) : emptyArray; + this.lastCachedUnresolvedImportsList = getUnresolvedImports(this.program, this.cachedUnresolvedImportsPerFile); } this.projectService.typingsCache.enqueueInstallTypingsForProject(this, this.lastCachedUnresolvedImportsList, hasAddedorRemovedFiles); @@ -1194,6 +1151,27 @@ namespace ts.server { } } + function getUnresolvedImports(program: Program, cachedUnresolvedImportsPerFile: Map>): SortedReadonlyArray { + const ambientModules = program.getTypeChecker().getAmbientModules().map(mod => stripQuotes(mod.getName())); + return toDeduplicatedSortedArray(flatMap(program.getSourceFiles(), sourceFile => + extractUnresolvedImportsFromSourceFile(sourceFile, ambientModules, cachedUnresolvedImportsPerFile))); + } + function extractUnresolvedImportsFromSourceFile(file: SourceFile, ambientModules: ReadonlyArray, cachedUnresolvedImportsPerFile: Map>): ReadonlyArray { + return getOrUpdate(cachedUnresolvedImportsPerFile, file.path, () => { + if (!file.resolvedModules) return emptyArray; + let unresolvedImports: string[] | undefined; + file.resolvedModules.forEach((resolvedModule, name) => { + // pick unresolved non-relative names + if ((!resolvedModule || !resolutionExtensionIsTSOrJson(resolvedModule.extension)) && + !isExternalModuleNameRelative(name) && + !ambientModules.some(m => m === name)) { + unresolvedImports = append(unresolvedImports, parsePackageName(name).packageName); + } + }); + return unresolvedImports || emptyArray; + }); + } + /** * If a file is opened and no tsconfig (or jsconfig) is found, * the file and its imports/references are put into an InferredProject. From 022fb48bb378011251024f3b48090deb7156b55d Mon Sep 17 00:00:00 2001 From: Andy Hanson Date: Mon, 29 Oct 2018 12:01:57 -0700 Subject: [PATCH 2/2] Revert if condition --- src/server/project.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/server/project.ts b/src/server/project.ts index 661ed6c30f2e7..7e45ab27e5950 100644 --- a/src/server/project.ts +++ b/src/server/project.ts @@ -1153,7 +1153,7 @@ namespace ts.server { function getUnresolvedImports(program: Program, cachedUnresolvedImportsPerFile: Map>): SortedReadonlyArray { const ambientModules = program.getTypeChecker().getAmbientModules().map(mod => stripQuotes(mod.getName())); - return toDeduplicatedSortedArray(flatMap(program.getSourceFiles(), sourceFile => + return toDeduplicatedSortedArray(flatMapToMutable(program.getSourceFiles(), sourceFile => extractUnresolvedImportsFromSourceFile(sourceFile, ambientModules, cachedUnresolvedImportsPerFile))); } function extractUnresolvedImportsFromSourceFile(file: SourceFile, ambientModules: ReadonlyArray, cachedUnresolvedImportsPerFile: Map>): ReadonlyArray { @@ -1162,9 +1162,7 @@ namespace ts.server { let unresolvedImports: string[] | undefined; file.resolvedModules.forEach((resolvedModule, name) => { // pick unresolved non-relative names - if ((!resolvedModule || !resolutionExtensionIsTSOrJson(resolvedModule.extension)) && - !isExternalModuleNameRelative(name) && - !ambientModules.some(m => m === name)) { + if (!resolvedModule && !isExternalModuleNameRelative(name) && !ambientModules.some(m => m === name)) { unresolvedImports = append(unresolvedImports, parsePackageName(name).packageName); } });