From a9e619cd075e5a6d14ccbad3db178bcfecfa7ffa Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Mon, 7 Nov 2022 12:58:11 -0800 Subject: [PATCH] TypeReference directive reuse --- src/compiler/moduleNameResolver.ts | 4 +- src/compiler/program.ts | 116 +++++- src/compiler/resolutionCache.ts | 31 +- src/compiler/types.ts | 11 +- src/compiler/utilities.ts | 8 +- src/compiler/watchPublic.ts | 4 +- src/server/project.ts | 4 +- src/services/types.ts | 2 +- .../unittests/reuseProgramStructure.ts | 31 +- .../unittests/tscWatch/moduleResolution.ts | 89 +++++ .../reference/api/tsserverlibrary.d.ts | 16 +- tests/baselines/reference/api/typescript.d.ts | 14 +- .../type-reference-resolutions-reuse.js | 359 ++++++++++++++++++ 13 files changed, 621 insertions(+), 68 deletions(-) create mode 100644 tests/baselines/reference/tscWatch/moduleResolution/type-reference-resolutions-reuse.js diff --git a/src/compiler/moduleNameResolver.ts b/src/compiler/moduleNameResolver.ts index 100e399004da7..9e197b59a6bd5 100644 --- a/src/compiler/moduleNameResolver.ts +++ b/src/compiler/moduleNameResolver.ts @@ -773,9 +773,9 @@ namespace ts { } /* @internal */ - export function getResolutionName(entry: FileReference | StringLiteralLike) { + export function getResolutionName(entry: string | FileReference | StringLiteralLike) { // We lower-case all type references because npm automatically lowercases all packages. See GH#9824. - return isStringLiteralLike(entry) ? entry.text : entry.fileName.toLowerCase(); + return !isString(entry) ? isStringLiteralLike(entry) ? entry.text : toFileNameLowerCase(entry.fileName) : entry; } /* @internal */ diff --git a/src/compiler/program.ts b/src/compiler/program.ts index 85d34e9106d57..f4b644467d843 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -501,8 +501,7 @@ namespace ts { for (const name of names) { let result: T; const mode = getModeForFileReference(name, containingFileMode); - // We lower-case all type references because npm automatically lowercases all packages. See GH#9824. - const strName = isString(name) ? name : name.fileName.toLowerCase(); + const strName = getResolutionName(name); const cacheKey = mode !== undefined ? `${mode}|${strName}` : strName; if (cache.has(cacheKey)) { result = cache.get(cacheKey)!; @@ -1138,9 +1137,16 @@ namespace ts { loadWithModeAwareCache(moduleNames, containingFile, containingFileName, redirectedReference, resolutionInfo, loader); } - let actualResolveTypeReferenceDirectiveNamesWorker: (typeDirectiveNames: string[] | readonly FileReference[], containingFile: string, redirectedReference?: ResolvedProjectReference, containingFileMode?: SourceFile["impliedNodeFormat"] | undefined) => (ResolvedTypeReferenceDirective | undefined)[]; + let actualResolveTypeReferenceDirectiveNamesWorker: ( + typeDirectiveNames: string[] | readonly FileReference[], + containingFile: string, + redirectedReference: ResolvedProjectReference | undefined, + containingFileMode: SourceFile["impliedNodeFormat"] | undefined, + resolutionInfo: TypeReferenceDirectiveResolutionInfo | undefined, + ) => (ResolvedTypeReferenceDirective | undefined)[]; if (host.resolveTypeReferenceDirectives) { - actualResolveTypeReferenceDirectiveNamesWorker = (typeDirectiveNames, containingFile, redirectedReference, containingFileMode) => host.resolveTypeReferenceDirectives!(Debug.checkEachDefined(typeDirectiveNames), containingFile, redirectedReference, options, containingFileMode); + actualResolveTypeReferenceDirectiveNamesWorker = (typeDirectiveNames, containingFile, redirectedReference, containingFileMode, resolutionInfo) => + host.resolveTypeReferenceDirectives!(Debug.checkEachDefined(typeDirectiveNames), containingFile, redirectedReference, options, containingFileMode, resolutionInfo); } else { typeReferenceDirectiveResolutionCache = createTypeReferenceDirectiveResolutionCache(currentDirectory, getCanonicalFileName, /*options*/ undefined, moduleResolutionCache?.getPackageJsonInfoCache()); @@ -1254,7 +1260,7 @@ namespace ts { // This containingFilename needs to match with the one used in managed-side const containingDirectory = options.configFilePath ? getDirectoryPath(options.configFilePath) : host.getCurrentDirectory(); const containingFilename = combinePaths(containingDirectory, inferredTypesContainingFile); - const resolutions = resolveTypeReferenceDirectiveNamesWorker(typeReferences, containingFilename); + const resolutions = resolveTypeReferenceDirectiveNamesReusingOldState(typeReferences, containingFilename); for (let i = 0; i < typeReferences.length; i++) { // under node16/nodenext module resolution, load `types`/ata include names as cjs resolution results by passing an `undefined` mode processTypeReferenceDirective(typeReferences[i], /*mode*/ undefined, resolutions[i], { kind: FileIncludeKind.AutomaticTypeDirectiveFile, typeReference: typeReferences[i], packageId: resolutions[i]?.packageId }); @@ -1452,14 +1458,14 @@ namespace ts { return result; } - function resolveTypeReferenceDirectiveNamesWorker(typeDirectiveNames: string[] | readonly FileReference[], containingFile: string | SourceFile): readonly (ResolvedTypeReferenceDirective | undefined)[] { + function resolveTypeReferenceDirectiveNamesWorker(typeDirectiveNames: string[] | readonly FileReference[], containingFile: string | SourceFile, resolutionInfo: TypeReferenceDirectiveResolutionInfo | undefined): readonly (ResolvedTypeReferenceDirective | undefined)[] { if (!typeDirectiveNames.length) return []; const containingFileName = !isString(containingFile) ? getNormalizedAbsolutePath(containingFile.originalFileName, currentDirectory) : containingFile; const redirectedReference = !isString(containingFile) ? getRedirectReferenceForResolution(containingFile) : undefined; const containingFileMode = !isString(containingFile) ? containingFile.impliedNodeFormat : undefined; tracing?.push(tracing.Phase.Program, "resolveTypeReferenceDirectiveNamesWorker", { containingFileName }); performance.mark("beforeResolveTypeReference"); - const result = actualResolveTypeReferenceDirectiveNamesWorker(typeDirectiveNames, containingFileName, redirectedReference, containingFileMode); + const result = actualResolveTypeReferenceDirectiveNamesWorker(typeDirectiveNames, containingFileName, redirectedReference, containingFileMode, resolutionInfo); performance.mark("afterResolveTypeReference"); performance.measure("ResolveTypeReference", "beforeResolveTypeReference", "afterResolveTypeReference"); tracing?.pop(); @@ -1695,6 +1701,96 @@ namespace ts { } } + function resolveTypeReferenceDirectiveNamesReusingOldState(typeDirectiveNames: readonly FileReference[], containingFile: SourceFile): readonly (ResolvedTypeReferenceDirective | undefined)[]; + function resolveTypeReferenceDirectiveNamesReusingOldState(typeDirectiveNames: string[], containingFile: string): readonly (ResolvedTypeReferenceDirective | undefined)[]; + function resolveTypeReferenceDirectiveNamesReusingOldState(typeDirectiveNames: string[] | readonly FileReference[], containingFile: string | SourceFile): readonly (ResolvedTypeReferenceDirective | undefined)[] { + if (structureIsReused === StructureIsReused.Not) { + // If the old program state does not permit reusing resolutions and `file` does not contain locally defined ambient modules, + // the best we can do is fallback to the default logic. + return resolveTypeReferenceDirectiveNamesWorker(typeDirectiveNames, containingFile, /*resolutionInfo*/ undefined); + } + + const oldSourceFile = !isString(containingFile) ? oldProgram && oldProgram.getSourceFile(containingFile.fileName) : undefined; + if (!isString(containingFile)) { + if (oldSourceFile !== containingFile && containingFile.resolvedTypeReferenceDirectiveNames) { + // `file` was created for the new program. + // + // We only set `file.resolvedTypeReferenceDirectiveNames` via work from the current function, + // so it is defined iff we already called the current function on `file`. + // That call happened no later than the creation of the `file` object, + // which per above occurred during the current program creation. + // Since we assume the filesystem does not change during program creation, + // it is safe to reuse resolutions from the earlier call. + const result: (ResolvedTypeReferenceDirective | undefined)[] = []; + for (const typeDirectiveName of typeDirectiveNames as readonly FileReference[]) { + // We lower-case all type references because npm automatically lowercases all packages. See GH#9824. + const resolvedTypeReferenceDirective = containingFile.resolvedTypeReferenceDirectiveNames.get(getResolutionName(typeDirectiveName), typeDirectiveName.resolutionMode || containingFile.impliedNodeFormat); + result.push(resolvedTypeReferenceDirective); + } + return result; + } + } + + /** An ordered list of module names for which we cannot recover the resolution. */ + let unknownTypeReferenceDirectiveNames: string[] | FileReference[] | undefined; + let result: (ResolvedTypeReferenceDirective | undefined)[] | undefined; + let reusedNames: (string | FileReference)[] | undefined; + const containingSourceFile = !isString(containingFile) ? containingFile : undefined; + const canReuseResolutions = !isString(containingFile) ? + containingFile === oldSourceFile && !hasInvalidatedResolutions(oldSourceFile.path) : + !hasInvalidatedResolutions(toPath(containingFile)); + for (let i = 0; i < typeDirectiveNames.length; i++) { + const entry = typeDirectiveNames[i]; + if (canReuseResolutions) { + const typeDirectiveName = getResolutionName(entry); + const mode = getModeForFileReference(entry, containingSourceFile?.impliedNodeFormat); + const oldResolvedTypeReferenceDirective = getResolvedTypeReferenceDirective(oldSourceFile, typeDirectiveName, mode); + if (oldResolvedTypeReferenceDirective) { + if (isTraceEnabled(options, host)) { + trace(host, + oldResolvedTypeReferenceDirective.packageId ? + Diagnostics.Reusing_resolution_of_type_reference_directive_0_from_1_of_old_program_it_was_successfully_resolved_to_2_with_Package_ID_3 : + Diagnostics.Reusing_resolution_of_type_reference_directive_0_from_1_of_old_program_it_was_successfully_resolved_to_2, + typeDirectiveName, + !isString(containingFile) ? getNormalizedAbsolutePath(containingFile.originalFileName, currentDirectory) : containingFile, + oldResolvedTypeReferenceDirective.resolvedFileName, + oldResolvedTypeReferenceDirective.packageId && packageIdToString(oldResolvedTypeReferenceDirective.packageId) + ); + } + (result ??= new Array(typeDirectiveNames.length))[i] = oldResolvedTypeReferenceDirective; + (reusedNames ??= []).push(entry); + continue; + } + } + // Resolution failed in the old program, or resolved to an ambient module for which we can't reuse the result. + (unknownTypeReferenceDirectiveNames ??= []).push(entry as FileReference & string); + } + + if (!unknownTypeReferenceDirectiveNames) return result || emptyArray; + const resolutions = resolveTypeReferenceDirectiveNamesWorker( + unknownTypeReferenceDirectiveNames, + containingFile, + { names: unknownTypeReferenceDirectiveNames, reusedNames } + ); + + // Combine results of resolutions + if (!result) { + // There were no unresolved resolutions. + Debug.assert(resolutions.length === typeDirectiveNames.length); + return resolutions; + } + + let j = 0; + for (let i = 0; i < result.length; i++) { + if (!result[i]) { + result[i] = resolutions[j]; + j++; + } + } + Debug.assert(j === resolutions.length); + return result; + } + function canReuseProjectReferences(): boolean { return !forEachProjectReference( oldProgram!.getProjectReferences(), @@ -1898,7 +1994,7 @@ namespace ts { newSourceFile.resolvedModules = oldSourceFile.resolvedModules; } const typesReferenceDirectives = newSourceFile.typeReferenceDirectives; - const typeReferenceResolutions = resolveTypeReferenceDirectiveNamesWorker(typesReferenceDirectives, newSourceFile); + const typeReferenceResolutions = resolveTypeReferenceDirectiveNamesReusingOldState(typesReferenceDirectives, newSourceFile); // ensure that types resolutions are still correct const typeReferenceResolutionsChanged = hasChangesInResolutions(typesReferenceDirectives, newSourceFile, typeReferenceResolutions, oldSourceFile.resolvedTypeReferenceDirectiveNames, typeDirectiveIsEqualTo); if (typeReferenceResolutionsChanged) { @@ -3165,13 +3261,13 @@ namespace ts { return; } - const resolutions = resolveTypeReferenceDirectiveNamesWorker(typeDirectives, file); + const resolutions = resolveTypeReferenceDirectiveNamesReusingOldState(typeDirectives, file); for (let index = 0; index < typeDirectives.length; index++) { const ref = file.typeReferenceDirectives[index]; const resolvedTypeReferenceDirective = resolutions[index]; // store resolved type directive on the file const fileName = toFileNameLowerCase(ref.fileName); - setResolvedTypeReferenceDirective(file, fileName, resolvedTypeReferenceDirective); + setResolvedTypeReferenceDirective(file, fileName, resolvedTypeReferenceDirective, getModeForFileReference(ref, file.impliedNodeFormat)); const mode = ref.resolutionMode || file.impliedNodeFormat; if (mode && getEmitModuleResolutionKind(options) !== ModuleResolutionKind.Node16 && getEmitModuleResolutionKind(options) !== ModuleResolutionKind.NodeNext) { programDiagnostics.add(createDiagnosticForRange(file, ref, Diagnostics.resolution_mode_assertions_are_only_supported_when_moduleResolution_is_node16_or_nodenext)); diff --git a/src/compiler/resolutionCache.ts b/src/compiler/resolutionCache.ts index 6953ebc845c86..53b66eedd65f8 100644 --- a/src/compiler/resolutionCache.ts +++ b/src/compiler/resolutionCache.ts @@ -14,7 +14,13 @@ namespace ts { resolutionInfo: ModuleResolutionInfo | undefined ): (ResolvedModuleFull | undefined)[]; getResolvedModuleWithFailedLookupLocationsFromCache(moduleName: string, containingFile: string, resolutionMode?: ModuleKind.CommonJS | ModuleKind.ESNext): CachedResolvedModuleWithFailedLookupLocations | undefined; - resolveTypeReferenceDirectives(typeDirectiveNames: string[] | readonly FileReference[], containingFile: string, redirectedReference?: ResolvedProjectReference, containingFileMode?: SourceFile["impliedNodeFormat"]): (ResolvedTypeReferenceDirective | undefined)[]; + resolveTypeReferenceDirectives( + typeDirectiveNames: string[] | readonly FileReference[], + containingFile: string, + redirectedReference: ResolvedProjectReference | undefined, + containingFileMode: SourceFile["impliedNodeFormat"] | undefined, + resolutionInfo: TypeReferenceDirectiveResolutionInfo | undefined, + ): (ResolvedTypeReferenceDirective | undefined)[]; invalidateResolutionsOfFailedLookupLocations(): boolean; invalidateResolutionOfFile(filePath: Path): void; @@ -416,7 +422,7 @@ namespace ts { getResolutionWithResolvedFileName: GetResolutionWithResolvedFileName; shouldRetryResolution: (t: T) => boolean; reusedNames?: readonly string[]; - resolutionInfo?: ModuleResolutionInfo; + resolutionInfo?: ModuleResolutionInfo | TypeReferenceDirectiveResolutionInfo; logChanges?: boolean; containingSourceFile?: SourceFile; containingSourceFileMode?: SourceFile["impliedNodeFormat"]; @@ -450,7 +456,7 @@ namespace ts { const seenNamesInFile = createModeAwareCache(); let i = 0; for (const entry of containingSourceFile && resolutionInfo ? resolutionInfo.names : names) { - const name = !isString(entry) ? getResolutionName(entry) : entry; + const name = getResolutionName(entry); // Imports supply a `containingSourceFile` but no `containingSourceFileMode` - it would be redundant // they require calculating the mode for a given import from it's position in the resolution table, since a given // import's syntax may override the file's default mode. @@ -547,7 +553,13 @@ namespace ts { } if (containingSourceFile && resolutionInfo) { - resolutionInfo.reusedNames?.forEach(literal => seenNamesInFile.set(literal.text, getModeForUsageLocation(containingSourceFile, literal), true)); + resolutionInfo.reusedNames?.forEach(entry => seenNamesInFile.set( + getResolutionName(entry), + !isString(entry) && isStringLiteralLike(entry) ? + getModeForUsageLocation(containingSourceFile, entry) : + getModeForFileReference(entry, containingSourceFile.impliedNodeFormat), + true, + )); reusedNames = undefined; } if (resolutionsInFile.size() !== seenNamesInFile.size()) { @@ -581,7 +593,13 @@ namespace ts { } } - function resolveTypeReferenceDirectives(typeDirectiveNames: string[] | readonly FileReference[], containingFile: string, redirectedReference?: ResolvedProjectReference, containingFileMode?: SourceFile["impliedNodeFormat"]): (ResolvedTypeReferenceDirective | undefined)[] { + function resolveTypeReferenceDirectives( + typeDirectiveNames: string[] | readonly FileReference[], + containingFile: string, + redirectedReference?: ResolvedProjectReference, + containingFileMode?: SourceFile["impliedNodeFormat"], + resolutionInfo?: TypeReferenceDirectiveResolutionInfo, + ): (ResolvedTypeReferenceDirective | undefined)[] { return resolveNamesWithLocalCache({ names: typeDirectiveNames, containingFile, @@ -591,7 +609,8 @@ namespace ts { loader: resolveTypeReferenceDirective, getResolutionWithResolvedFileName: getResolvedTypeReferenceDirective, shouldRetryResolution: resolution => resolution.resolvedTypeReferenceDirective === undefined, - containingSourceFileMode: containingFileMode + containingSourceFileMode: containingFileMode, + resolutionInfo, }); } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 9f6cd20edadc6..041c0edd5e27f 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -7193,11 +7193,14 @@ namespace ts { /* @internal */ export type HasChangedAutomaticTypeDirectiveNames = () => boolean; - export interface ModuleResolutionInfo { - names: readonly StringLiteralLike[]; - reusedNames: readonly StringLiteralLike[] | undefined; + export interface ResolutionInfo { + names: readonly T[]; + reusedNames: readonly T[] | undefined; } + export type ModuleResolutionInfo = ResolutionInfo; + export type TypeReferenceDirectiveResolutionInfo = ResolutionInfo; + export interface CompilerHost extends ModuleResolutionHost { getSourceFile(fileName: string, languageVersionOrOptions: ScriptTarget | CreateSourceFileOptions, onError?: (message: string) => void, shouldCreateNewSourceFile?: boolean): SourceFile | undefined; getSourceFileByPath?(fileName: string, path: Path, languageVersionOrOptions: ScriptTarget | CreateSourceFileOptions, onError?: (message: string) => void, shouldCreateNewSourceFile?: boolean): SourceFile | undefined; @@ -7226,7 +7229,7 @@ namespace ts { /** * This method is a companion for 'resolveModuleNames' and is used to resolve 'types' references to actual type declaration files */ - resolveTypeReferenceDirectives?(typeReferenceDirectiveNames: string[] | readonly FileReference[], containingFile: string, redirectedReference: ResolvedProjectReference | undefined, options: CompilerOptions, containingFileMode?: SourceFile["impliedNodeFormat"] | undefined): (ResolvedTypeReferenceDirective | undefined)[]; + resolveTypeReferenceDirectives?(typeReferenceDirectiveNames: string[] | readonly FileReference[], containingFile: string, redirectedReference: ResolvedProjectReference | undefined, options: CompilerOptions, containingFileMode?: SourceFile["impliedNodeFormat"] | undefined, resolutionInfo?: TypeReferenceDirectiveResolutionInfo): (ResolvedTypeReferenceDirective | undefined)[]; getEnvironmentVariable?(name: string): string | undefined; /* @internal */ onReleaseOldSourceFile?(oldSourceFile: SourceFile, oldOptions: CompilerOptions, hasSourceFileByPath: boolean): void; /* @internal */ onReleaseParsedCommandLine?(configFileName: string, oldResolvedRef: ResolvedProjectReference | undefined, optionOptions: CompilerOptions): void; diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index f6595c18e836a..0bad3db0ab171 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -170,12 +170,16 @@ namespace ts { sourceFile.resolvedModules.set(moduleNameText, mode, resolvedModule); } - export function setResolvedTypeReferenceDirective(sourceFile: SourceFile, typeReferenceDirectiveName: string, resolvedTypeReferenceDirective?: ResolvedTypeReferenceDirective): void { + export function setResolvedTypeReferenceDirective(sourceFile: SourceFile, typeReferenceDirectiveName: string, resolvedTypeReferenceDirective: ResolvedTypeReferenceDirective | undefined, mode: ModuleKind.CommonJS | ModuleKind.ESNext | undefined): void { if (!sourceFile.resolvedTypeReferenceDirectiveNames) { sourceFile.resolvedTypeReferenceDirectiveNames = createModeAwareCache(); } - sourceFile.resolvedTypeReferenceDirectiveNames.set(typeReferenceDirectiveName, /*mode*/ undefined, resolvedTypeReferenceDirective); + sourceFile.resolvedTypeReferenceDirectiveNames.set(typeReferenceDirectiveName, mode, resolvedTypeReferenceDirective); + } + + export function getResolvedTypeReferenceDirective(sourceFile: SourceFile | undefined, typeReferenceDirectiveName: string, mode: ModuleKind.CommonJS | ModuleKind.ESNext | undefined): ResolvedTypeReferenceDirective | undefined { + return sourceFile?.resolvedTypeReferenceDirectiveNames?.get(typeReferenceDirectiveName, mode); } export function projectReferenceIsEqualTo(oldRef: ProjectReference, newRef: ProjectReference) { diff --git a/src/compiler/watchPublic.ts b/src/compiler/watchPublic.ts index 8ce7ccacedde7..ae01926ed4cbe 100644 --- a/src/compiler/watchPublic.ts +++ b/src/compiler/watchPublic.ts @@ -111,7 +111,7 @@ namespace ts { /** If provided, used to resolve the module names, otherwise typescript's default module resolution */ resolveModuleNames?(moduleNames: string[], containingFile: string, reusedNames: string[] | undefined, redirectedReference: ResolvedProjectReference | undefined, options: CompilerOptions, containingSourceFile?: SourceFile, resolutionInfo?: ModuleResolutionInfo): (ResolvedModule | undefined)[]; /** If provided, used to resolve type reference directives, otherwise typescript's default resolution */ - resolveTypeReferenceDirectives?(typeReferenceDirectiveNames: string[] | readonly FileReference[], containingFile: string, redirectedReference: ResolvedProjectReference | undefined, options: CompilerOptions, containingFileMode?: SourceFile["impliedNodeFormat"] | undefined): (ResolvedTypeReferenceDirective | undefined)[]; + resolveTypeReferenceDirectives?(typeReferenceDirectiveNames: string[] | readonly FileReference[], containingFile: string, redirectedReference: ResolvedProjectReference | undefined, options: CompilerOptions, containingFileMode?: SourceFile["impliedNodeFormat"] | undefined, resolutionInfo?: TypeReferenceDirectiveResolutionInfo): (ResolvedTypeReferenceDirective | undefined)[]; /** If provided along with custom resolveModuleNames or resolveTypeReferenceDirectives, used to determine if unchanged file path needs to re-resolve modules/type reference directives */ hasInvalidatedResolutions?(filePath: Path): boolean; /** @@ -368,7 +368,7 @@ namespace ts { ((moduleNames, containingFile, reusedNames, redirectedReference, _options, sourceFile, resolutionInfo) => resolutionCache.resolveModuleNames(moduleNames, containingFile, reusedNames, redirectedReference, sourceFile, resolutionInfo)); compilerHost.resolveTypeReferenceDirectives = host.resolveTypeReferenceDirectives ? ((...args) => host.resolveTypeReferenceDirectives!(...args)) : - ((typeDirectiveNames, containingFile, redirectedReference, _options, containingFileMode) => resolutionCache.resolveTypeReferenceDirectives(typeDirectiveNames, containingFile, redirectedReference, containingFileMode)); + ((typeDirectiveNames, containingFile, redirectedReference, _options, containingFileMode, resolutionInfo) => resolutionCache.resolveTypeReferenceDirectives(typeDirectiveNames, containingFile, redirectedReference, containingFileMode, resolutionInfo)); compilerHost.getModuleResolutionCache = host.resolveModuleNames ? maybeBind(host, host.getModuleResolutionCache) : (() => resolutionCache.getModuleResolutionCache()); diff --git a/src/server/project.ts b/src/server/project.ts index 1c339d4202f53..21899a937a62d 100644 --- a/src/server/project.ts +++ b/src/server/project.ts @@ -518,8 +518,8 @@ namespace ts.server { return this.resolutionCache.getResolvedModuleWithFailedLookupLocationsFromCache(moduleName, containingFile, resolutionMode); } - resolveTypeReferenceDirectives(typeDirectiveNames: string[] | FileReference[], containingFile: string, redirectedReference?: ResolvedProjectReference, _options?: CompilerOptions, containingFileMode?: SourceFile["impliedNodeFormat"] | undefined): (ResolvedTypeReferenceDirective | undefined)[] { - return this.resolutionCache.resolveTypeReferenceDirectives(typeDirectiveNames, containingFile, redirectedReference, containingFileMode); + resolveTypeReferenceDirectives(typeDirectiveNames: string[] | FileReference[], containingFile: string, redirectedReference?: ResolvedProjectReference, _options?: CompilerOptions, containingFileMode?: SourceFile["impliedNodeFormat"] | undefined, resolutionInfo?: TypeReferenceDirectiveResolutionInfo): (ResolvedTypeReferenceDirective | undefined)[] { + return this.resolutionCache.resolveTypeReferenceDirectives(typeDirectiveNames, containingFile, redirectedReference, containingFileMode, resolutionInfo); } directoryExists(path: string): boolean { diff --git a/src/services/types.ts b/src/services/types.ts index fdd692b5b2233..fc479591e3984 100644 --- a/src/services/types.ts +++ b/src/services/types.ts @@ -286,7 +286,7 @@ namespace ts { */ resolveModuleNames?(moduleNames: string[], containingFile: string, reusedNames: string[] | undefined, redirectedReference: ResolvedProjectReference | undefined, options: CompilerOptions, containingSourceFile?: SourceFile, resolutionInfo?: ModuleResolutionInfo): (ResolvedModule | undefined)[]; getResolvedModuleWithFailedLookupLocationsFromCache?(modulename: string, containingFile: string, resolutionMode?: ModuleKind.CommonJS | ModuleKind.ESNext): ResolvedModuleWithFailedLookupLocations | undefined; - resolveTypeReferenceDirectives?(typeDirectiveNames: string[] | FileReference[], containingFile: string, redirectedReference: ResolvedProjectReference | undefined, options: CompilerOptions, containingFileMode?: SourceFile["impliedNodeFormat"] | undefined): (ResolvedTypeReferenceDirective | undefined)[]; + resolveTypeReferenceDirectives?(typeDirectiveNames: string[] | FileReference[], containingFile: string, redirectedReference: ResolvedProjectReference | undefined, options: CompilerOptions, containingFileMode?: SourceFile["impliedNodeFormat"] | undefined, resolutionInfo?: TypeReferenceDirectiveResolutionInfo): (ResolvedTypeReferenceDirective | undefined)[]; /* @internal */ hasInvalidatedResolutions?: HasInvalidatedResolutions; /* @internal */ hasChangedAutomaticTypeDirectiveNames?: HasChangedAutomaticTypeDirectiveNames; /* @internal */ getGlobalTypingsCacheLocation?(): string | undefined; diff --git a/src/testRunner/unittests/reuseProgramStructure.ts b/src/testRunner/unittests/reuseProgramStructure.ts index eda2135323d9c..c9d660083f93d 100644 --- a/src/testRunner/unittests/reuseProgramStructure.ts +++ b/src/testRunner/unittests/reuseProgramStructure.ts @@ -692,11 +692,7 @@ namespace ts { "Explicitly specified module resolution kind: 'Classic'.", "File 'b1.ts' exist - use it as a name resolution result.", "======== Module name './b1' was successfully resolved to 'b1.ts'. ========", - "======== Resolving type reference directive 'typerefs2', containing file 'f2.ts', root directory 'node_modules/@types'. ========", - "Resolving with primary search path 'node_modules/@types'.", - "File 'node_modules/@types/typerefs2/package.json' does not exist.", - "File 'node_modules/@types/typerefs2/index.d.ts' exist - use it as a name resolution result.", - "======== Type reference directive 'typerefs2' was successfully resolved to 'node_modules/@types/typerefs2/index.d.ts', primary: true. ========", + "Reusing resolution of type reference directive 'typerefs2' from 'f2.ts' of old program, it was successfully resolved to 'node_modules/@types/typerefs2/index.d.ts'.", "Reusing resolution of module './b2' from 'f2.ts' of old program, it was successfully resolved to 'b2.ts'.", "Reusing resolution of module './f1' from 'f2.ts' of old program, it was successfully resolved to 'f1.ts'." ], "program2: reuse module resolutions in f2 since it is unchanged"); @@ -716,11 +712,7 @@ namespace ts { "Explicitly specified module resolution kind: 'Classic'.", "File 'b1.ts' exist - use it as a name resolution result.", "======== Module name './b1' was successfully resolved to 'b1.ts'. ========", - "======== Resolving type reference directive 'typerefs2', containing file 'f2.ts', root directory 'node_modules/@types'. ========", - "Resolving with primary search path 'node_modules/@types'.", - "File 'node_modules/@types/typerefs2/package.json' does not exist.", - "File 'node_modules/@types/typerefs2/index.d.ts' exist - use it as a name resolution result.", - "======== Type reference directive 'typerefs2' was successfully resolved to 'node_modules/@types/typerefs2/index.d.ts', primary: true. ========", + "Reusing resolution of type reference directive 'typerefs2' from 'f2.ts' of old program, it was successfully resolved to 'node_modules/@types/typerefs2/index.d.ts'.", "Reusing resolution of module './b2' from 'f2.ts' of old program, it was successfully resolved to 'b2.ts'.", "Reusing resolution of module './f1' from 'f2.ts' of old program, it was successfully resolved to 'f1.ts'." ], "program3: reuse module resolutions in f2 since it is unchanged"); @@ -741,11 +733,7 @@ namespace ts { "Explicitly specified module resolution kind: 'Classic'.", "File 'b1.ts' exist - use it as a name resolution result.", "======== Module name './b1' was successfully resolved to 'b1.ts'. ========", - "======== Resolving type reference directive 'typerefs2', containing file 'f2.ts', root directory 'node_modules/@types'. ========", - "Resolving with primary search path 'node_modules/@types'.", - "File 'node_modules/@types/typerefs2/package.json' does not exist.", - "File 'node_modules/@types/typerefs2/index.d.ts' exist - use it as a name resolution result.", - "======== Type reference directive 'typerefs2' was successfully resolved to 'node_modules/@types/typerefs2/index.d.ts', primary: true. ========", + "Reusing resolution of type reference directive 'typerefs2' from 'f2.ts' of old program, it was successfully resolved to 'node_modules/@types/typerefs2/index.d.ts'.", "Reusing resolution of module './b2' from 'f2.ts' of old program, it was successfully resolved to 'b2.ts'.", "Reusing resolution of module './f1' from 'f2.ts' of old program, it was successfully resolved to 'f1.ts'.", ], "program_4: reuse module resolutions in f2 since it is unchanged"); @@ -782,11 +770,7 @@ namespace ts { "Explicitly specified module resolution kind: 'Classic'.", "File 'b1.ts' exist - use it as a name resolution result.", "======== Module name './b1' was successfully resolved to 'b1.ts'. ========", - "======== Resolving type reference directive 'typerefs2', containing file 'f2.ts', root directory 'node_modules/@types'. ========", - "Resolving with primary search path 'node_modules/@types'.", - "File 'node_modules/@types/typerefs2/package.json' does not exist.", - "File 'node_modules/@types/typerefs2/index.d.ts' exist - use it as a name resolution result.", - "======== Type reference directive 'typerefs2' was successfully resolved to 'node_modules/@types/typerefs2/index.d.ts', primary: true. ========", + "Reusing resolution of type reference directive 'typerefs2' from 'f2.ts' of old program, it was successfully resolved to 'node_modules/@types/typerefs2/index.d.ts'.", "Reusing resolution of module './b2' from 'f2.ts' of old program, it was successfully resolved to 'b2.ts'.", "Reusing resolution of module './f1' from 'f2.ts' of old program, it was successfully resolved to 'f1.ts'.", ], "program_6: reuse module resolutions in f2 since it is unchanged"); @@ -802,12 +786,7 @@ namespace ts { assert.lengthOf(program7Diagnostics, expectedErrors, `removing import is noop with respect to program, so no change in diagnostics.`); assert.deepEqual(program7.host.getTrace(), [ - "======== Resolving type reference directive 'typerefs2', containing file 'f2.ts', root directory 'node_modules/@types'. ========", - "Resolving with primary search path 'node_modules/@types'.", - "File 'node_modules/@types/typerefs2/package.json' does not exist.", - "File 'node_modules/@types/typerefs2/index.d.ts' exist - use it as a name resolution result.", - "======== Type reference directive 'typerefs2' was successfully resolved to 'node_modules/@types/typerefs2/index.d.ts', primary: true. ========", - "Reusing resolution of module './b2' from 'f2.ts' of old program, it was successfully resolved to 'b2.ts'.", + "Reusing resolution of type reference directive 'typerefs2' from 'f2.ts' of old program, it was successfully resolved to 'node_modules/@types/typerefs2/index.d.ts'.", "Reusing resolution of module './b2' from 'f2.ts' of old program, it was successfully resolved to 'b2.ts'.", "Reusing resolution of module './f1' from 'f2.ts' of old program, it was successfully resolved to 'f1.ts'.", ], "program_7 should reuse module resolutions in f2 since it is unchanged"); } diff --git a/src/testRunner/unittests/tscWatch/moduleResolution.ts b/src/testRunner/unittests/tscWatch/moduleResolution.ts index 8361da8532cbd..ed00ec6e11088 100644 --- a/src/testRunner/unittests/tscWatch/moduleResolution.ts +++ b/src/testRunner/unittests/tscWatch/moduleResolution.ts @@ -326,5 +326,94 @@ namespace ts.tscWatch { } ] }); + + verifyTscWatch({ + scenario: "moduleResolution", + subScenario: "type reference resolutions reuse", + sys: () => createWatchedSystem([ + { + path: `${projectRoot}/tsconfig.json`, + content: JSON.stringify({ + compilerOptions: { moduleResolution: "node16" }, + }) + }, + { + path: `${projectRoot}/index.ts`, + content: Utils.dedent` + /// + /// + export interface LocalInterface extends RequireInterface {} + ` + }, + { + path: `${projectRoot}/a.ts`, + content: Utils.dedent` + export const x = 10; + ` + }, + { + path: `${projectRoot}/node_modules/pkg/package.json`, + content: JSON.stringify({ + name: "pkg", + version: "0.0.1", + exports: { + import: "./import.js", + require: "./require.js" + } + }) + }, + { + path: `${projectRoot}/node_modules/pkg/import.d.ts`, + content: Utils.dedent` + export {}; + declare global { + interface ImportInterface {} + } + ` + }, + { + path: `${projectRoot}/node_modules/pkg/require.d.ts`, + content: Utils.dedent` + export {}; + declare global { + interface RequireInterface {} + } + ` + }, + { + path: `${projectRoot}/node_modules/pkg1/package.json`, + content: JSON.stringify({ + name: "pkg1", + version: "0.0.1", + exports: { + import: "./import.js", + require: "./require.js" + } + }) + }, + { + path: `${projectRoot}/node_modules/pkg1/import.d.ts`, + content: Utils.dedent` + export {}; + declare global { + interface ImportInterface {} + } + ` + }, + { + path: `${projectRoot}/node_modules/@types/pkg2/index.d.ts`, + content: `export const x = 10;` + }, + libFile + ], { currentDirectory: projectRoot }), + commandLineArgs: ["-w", "--traceResolution"], + changes: [ + { + caption: "modify aFile by adding import", + change: sys => sys.prependFile(`${projectRoot}/a.ts`, `/// \n`), + timeouts: sys => sys.runQueuedTimeoutCallbacks(), + } + ] + }); }); } \ No newline at end of file diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index a0ffcb7706a95..31ef10362e6bd 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -3301,10 +3301,12 @@ declare namespace ts { readonly resolvedTypeReferenceDirective: ResolvedTypeReferenceDirective | undefined; readonly failedLookupLocations: string[]; } - export interface ModuleResolutionInfo { - names: readonly StringLiteralLike[]; - reusedNames: readonly StringLiteralLike[] | undefined; + export interface ResolutionInfo { + names: readonly T[]; + reusedNames: readonly T[] | undefined; } + export type ModuleResolutionInfo = ResolutionInfo; + export type TypeReferenceDirectiveResolutionInfo = ResolutionInfo; export interface CompilerHost extends ModuleResolutionHost { getSourceFile(fileName: string, languageVersionOrOptions: ScriptTarget | CreateSourceFileOptions, onError?: (message: string) => void, shouldCreateNewSourceFile?: boolean): SourceFile | undefined; getSourceFileByPath?(fileName: string, path: Path, languageVersionOrOptions: ScriptTarget | CreateSourceFileOptions, onError?: (message: string) => void, shouldCreateNewSourceFile?: boolean): SourceFile | undefined; @@ -3325,7 +3327,7 @@ declare namespace ts { /** * This method is a companion for 'resolveModuleNames' and is used to resolve 'types' references to actual type declaration files */ - resolveTypeReferenceDirectives?(typeReferenceDirectiveNames: string[] | readonly FileReference[], containingFile: string, redirectedReference: ResolvedProjectReference | undefined, options: CompilerOptions, containingFileMode?: SourceFile["impliedNodeFormat"] | undefined): (ResolvedTypeReferenceDirective | undefined)[]; + resolveTypeReferenceDirectives?(typeReferenceDirectiveNames: string[] | readonly FileReference[], containingFile: string, redirectedReference: ResolvedProjectReference | undefined, options: CompilerOptions, containingFileMode?: SourceFile["impliedNodeFormat"] | undefined, resolutionInfo?: TypeReferenceDirectiveResolutionInfo): (ResolvedTypeReferenceDirective | undefined)[]; getEnvironmentVariable?(name: string): string | undefined; /** If provided along with custom resolveModuleNames or resolveTypeReferenceDirectives, used to determine if unchanged file path needs to re-resolve modules/type reference directives */ hasInvalidatedResolutions?(filePath: Path): boolean; @@ -5450,7 +5452,7 @@ declare namespace ts { /** If provided, used to resolve the module names, otherwise typescript's default module resolution */ resolveModuleNames?(moduleNames: string[], containingFile: string, reusedNames: string[] | undefined, redirectedReference: ResolvedProjectReference | undefined, options: CompilerOptions, containingSourceFile?: SourceFile, resolutionInfo?: ModuleResolutionInfo): (ResolvedModule | undefined)[]; /** If provided, used to resolve type reference directives, otherwise typescript's default resolution */ - resolveTypeReferenceDirectives?(typeReferenceDirectiveNames: string[] | readonly FileReference[], containingFile: string, redirectedReference: ResolvedProjectReference | undefined, options: CompilerOptions, containingFileMode?: SourceFile["impliedNodeFormat"] | undefined): (ResolvedTypeReferenceDirective | undefined)[]; + resolveTypeReferenceDirectives?(typeReferenceDirectiveNames: string[] | readonly FileReference[], containingFile: string, redirectedReference: ResolvedProjectReference | undefined, options: CompilerOptions, containingFileMode?: SourceFile["impliedNodeFormat"] | undefined, resolutionInfo?: TypeReferenceDirectiveResolutionInfo): (ResolvedTypeReferenceDirective | undefined)[]; /** If provided along with custom resolveModuleNames or resolveTypeReferenceDirectives, used to determine if unchanged file path needs to re-resolve modules/type reference directives */ hasInvalidatedResolutions?(filePath: Path): boolean; /** @@ -5857,7 +5859,7 @@ declare namespace ts { getTypeRootsVersion?(): number; resolveModuleNames?(moduleNames: string[], containingFile: string, reusedNames: string[] | undefined, redirectedReference: ResolvedProjectReference | undefined, options: CompilerOptions, containingSourceFile?: SourceFile, resolutionInfo?: ModuleResolutionInfo): (ResolvedModule | undefined)[]; getResolvedModuleWithFailedLookupLocationsFromCache?(modulename: string, containingFile: string, resolutionMode?: ModuleKind.CommonJS | ModuleKind.ESNext): ResolvedModuleWithFailedLookupLocations | undefined; - resolveTypeReferenceDirectives?(typeDirectiveNames: string[] | FileReference[], containingFile: string, redirectedReference: ResolvedProjectReference | undefined, options: CompilerOptions, containingFileMode?: SourceFile["impliedNodeFormat"] | undefined): (ResolvedTypeReferenceDirective | undefined)[]; + resolveTypeReferenceDirectives?(typeDirectiveNames: string[] | FileReference[], containingFile: string, redirectedReference: ResolvedProjectReference | undefined, options: CompilerOptions, containingFileMode?: SourceFile["impliedNodeFormat"] | undefined, resolutionInfo?: TypeReferenceDirectiveResolutionInfo): (ResolvedTypeReferenceDirective | undefined)[]; getDirectories?(directoryName: string): string[]; /** * Gets a set of custom transformers to use during emit. @@ -10161,7 +10163,7 @@ declare namespace ts.server { resolveModuleNames(moduleNames: string[], containingFile: string, reusedNames?: string[], redirectedReference?: ResolvedProjectReference, _options?: CompilerOptions, containingSourceFile?: SourceFile, resolutionInfo?: ModuleResolutionInfo): (ResolvedModuleFull | undefined)[]; getModuleResolutionCache(): ModuleResolutionCache | undefined; getResolvedModuleWithFailedLookupLocationsFromCache(moduleName: string, containingFile: string, resolutionMode?: ModuleKind.CommonJS | ModuleKind.ESNext): ResolvedModuleWithFailedLookupLocations | undefined; - resolveTypeReferenceDirectives(typeDirectiveNames: string[] | FileReference[], containingFile: string, redirectedReference?: ResolvedProjectReference, _options?: CompilerOptions, containingFileMode?: SourceFile["impliedNodeFormat"] | undefined): (ResolvedTypeReferenceDirective | undefined)[]; + resolveTypeReferenceDirectives(typeDirectiveNames: string[] | FileReference[], containingFile: string, redirectedReference?: ResolvedProjectReference, _options?: CompilerOptions, containingFileMode?: SourceFile["impliedNodeFormat"] | undefined, resolutionInfo?: TypeReferenceDirectiveResolutionInfo): (ResolvedTypeReferenceDirective | undefined)[]; directoryExists(path: string): boolean; getDirectories(path: string): string[]; log(s: string): void; diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index cc8a0528dd95e..35b0f18168f33 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -3301,10 +3301,12 @@ declare namespace ts { readonly resolvedTypeReferenceDirective: ResolvedTypeReferenceDirective | undefined; readonly failedLookupLocations: string[]; } - export interface ModuleResolutionInfo { - names: readonly StringLiteralLike[]; - reusedNames: readonly StringLiteralLike[] | undefined; + export interface ResolutionInfo { + names: readonly T[]; + reusedNames: readonly T[] | undefined; } + export type ModuleResolutionInfo = ResolutionInfo; + export type TypeReferenceDirectiveResolutionInfo = ResolutionInfo; export interface CompilerHost extends ModuleResolutionHost { getSourceFile(fileName: string, languageVersionOrOptions: ScriptTarget | CreateSourceFileOptions, onError?: (message: string) => void, shouldCreateNewSourceFile?: boolean): SourceFile | undefined; getSourceFileByPath?(fileName: string, path: Path, languageVersionOrOptions: ScriptTarget | CreateSourceFileOptions, onError?: (message: string) => void, shouldCreateNewSourceFile?: boolean): SourceFile | undefined; @@ -3325,7 +3327,7 @@ declare namespace ts { /** * This method is a companion for 'resolveModuleNames' and is used to resolve 'types' references to actual type declaration files */ - resolveTypeReferenceDirectives?(typeReferenceDirectiveNames: string[] | readonly FileReference[], containingFile: string, redirectedReference: ResolvedProjectReference | undefined, options: CompilerOptions, containingFileMode?: SourceFile["impliedNodeFormat"] | undefined): (ResolvedTypeReferenceDirective | undefined)[]; + resolveTypeReferenceDirectives?(typeReferenceDirectiveNames: string[] | readonly FileReference[], containingFile: string, redirectedReference: ResolvedProjectReference | undefined, options: CompilerOptions, containingFileMode?: SourceFile["impliedNodeFormat"] | undefined, resolutionInfo?: TypeReferenceDirectiveResolutionInfo): (ResolvedTypeReferenceDirective | undefined)[]; getEnvironmentVariable?(name: string): string | undefined; /** If provided along with custom resolveModuleNames or resolveTypeReferenceDirectives, used to determine if unchanged file path needs to re-resolve modules/type reference directives */ hasInvalidatedResolutions?(filePath: Path): boolean; @@ -5450,7 +5452,7 @@ declare namespace ts { /** If provided, used to resolve the module names, otherwise typescript's default module resolution */ resolveModuleNames?(moduleNames: string[], containingFile: string, reusedNames: string[] | undefined, redirectedReference: ResolvedProjectReference | undefined, options: CompilerOptions, containingSourceFile?: SourceFile, resolutionInfo?: ModuleResolutionInfo): (ResolvedModule | undefined)[]; /** If provided, used to resolve type reference directives, otherwise typescript's default resolution */ - resolveTypeReferenceDirectives?(typeReferenceDirectiveNames: string[] | readonly FileReference[], containingFile: string, redirectedReference: ResolvedProjectReference | undefined, options: CompilerOptions, containingFileMode?: SourceFile["impliedNodeFormat"] | undefined): (ResolvedTypeReferenceDirective | undefined)[]; + resolveTypeReferenceDirectives?(typeReferenceDirectiveNames: string[] | readonly FileReference[], containingFile: string, redirectedReference: ResolvedProjectReference | undefined, options: CompilerOptions, containingFileMode?: SourceFile["impliedNodeFormat"] | undefined, resolutionInfo?: TypeReferenceDirectiveResolutionInfo): (ResolvedTypeReferenceDirective | undefined)[]; /** If provided along with custom resolveModuleNames or resolveTypeReferenceDirectives, used to determine if unchanged file path needs to re-resolve modules/type reference directives */ hasInvalidatedResolutions?(filePath: Path): boolean; /** @@ -5857,7 +5859,7 @@ declare namespace ts { getTypeRootsVersion?(): number; resolveModuleNames?(moduleNames: string[], containingFile: string, reusedNames: string[] | undefined, redirectedReference: ResolvedProjectReference | undefined, options: CompilerOptions, containingSourceFile?: SourceFile, resolutionInfo?: ModuleResolutionInfo): (ResolvedModule | undefined)[]; getResolvedModuleWithFailedLookupLocationsFromCache?(modulename: string, containingFile: string, resolutionMode?: ModuleKind.CommonJS | ModuleKind.ESNext): ResolvedModuleWithFailedLookupLocations | undefined; - resolveTypeReferenceDirectives?(typeDirectiveNames: string[] | FileReference[], containingFile: string, redirectedReference: ResolvedProjectReference | undefined, options: CompilerOptions, containingFileMode?: SourceFile["impliedNodeFormat"] | undefined): (ResolvedTypeReferenceDirective | undefined)[]; + resolveTypeReferenceDirectives?(typeDirectiveNames: string[] | FileReference[], containingFile: string, redirectedReference: ResolvedProjectReference | undefined, options: CompilerOptions, containingFileMode?: SourceFile["impliedNodeFormat"] | undefined, resolutionInfo?: TypeReferenceDirectiveResolutionInfo): (ResolvedTypeReferenceDirective | undefined)[]; getDirectories?(directoryName: string): string[]; /** * Gets a set of custom transformers to use during emit. diff --git a/tests/baselines/reference/tscWatch/moduleResolution/type-reference-resolutions-reuse.js b/tests/baselines/reference/tscWatch/moduleResolution/type-reference-resolutions-reuse.js new file mode 100644 index 0000000000000..30637c5340476 --- /dev/null +++ b/tests/baselines/reference/tscWatch/moduleResolution/type-reference-resolutions-reuse.js @@ -0,0 +1,359 @@ +Input:: +//// [/user/username/projects/myproject/tsconfig.json] +{"compilerOptions":{"moduleResolution":"node16"}} + +//// [/user/username/projects/myproject/index.ts] +/// +/// +export interface LocalInterface extends RequireInterface {} + + +//// [/user/username/projects/myproject/a.ts] +export const x = 10; + + +//// [/user/username/projects/myproject/node_modules/pkg/package.json] +{"name":"pkg","version":"0.0.1","exports":{"import":"./import.js","require":"./require.js"}} + +//// [/user/username/projects/myproject/node_modules/pkg/import.d.ts] +export {}; +declare global { + interface ImportInterface {} +} + + +//// [/user/username/projects/myproject/node_modules/pkg/require.d.ts] +export {}; +declare global { + interface RequireInterface {} +} + + +//// [/user/username/projects/myproject/node_modules/pkg1/package.json] +{"name":"pkg1","version":"0.0.1","exports":{"import":"./import.js","require":"./require.js"}} + +//// [/user/username/projects/myproject/node_modules/pkg1/import.d.ts] +export {}; +declare global { + interface ImportInterface {} +} + + +//// [/user/username/projects/myproject/node_modules/@types/pkg2/index.d.ts] +export const x = 10; + +//// [/a/lib/lib.d.ts] +/// +interface Boolean {} +interface Function {} +interface CallableFunction {} +interface NewableFunction {} +interface IArguments {} +interface Number { toExponential: any; } +interface Object {} +interface RegExp {} +interface String { charAt: any; } +interface Array { length: number; [n: number]: T; } + + +/a/lib/tsc.js -w --traceResolution +Output:: +>> Screen clear +[12:00:45 AM] Starting compilation in watch mode... + +File '/user/username/projects/myproject/package.json' does not exist. +File '/user/username/projects/package.json' does not exist. +File '/user/username/package.json' does not exist. +File '/user/package.json' does not exist. +File '/package.json' does not exist. +File '/user/username/projects/myproject/package.json' does not exist according to earlier cached lookups. +File '/user/username/projects/package.json' does not exist according to earlier cached lookups. +File '/user/username/package.json' does not exist according to earlier cached lookups. +File '/user/package.json' does not exist according to earlier cached lookups. +File '/package.json' does not exist according to earlier cached lookups. +======== Resolving type reference directive 'pkg', containing file '/user/username/projects/myproject/index.ts', root directory '/user/username/projects/myproject/node_modules/@types'. ======== +Resolving with primary search path '/user/username/projects/myproject/node_modules/@types'. +Looking up in 'node_modules' folder, initial location '/user/username/projects/myproject'. +Found 'package.json' at '/user/username/projects/myproject/node_modules/pkg/package.json'. +'package.json' does not have a 'typesVersions' field. +Matched 'exports' condition 'import'. +Using 'exports' subpath '.' with target './import.js'. +File name '/user/username/projects/myproject/node_modules/pkg/import.js' has a '.js' extension - stripping it. +File '/user/username/projects/myproject/node_modules/pkg/import.d.ts' exist - use it as a name resolution result. +Resolving real path for '/user/username/projects/myproject/node_modules/pkg/import.d.ts', result '/user/username/projects/myproject/node_modules/pkg/import.d.ts'. +======== Type reference directive 'pkg' was successfully resolved to '/user/username/projects/myproject/node_modules/pkg/import.d.ts' with Package ID 'pkg/import.d.ts@0.0.1', primary: false. ======== +======== Resolving type reference directive 'pkg1', containing file '/user/username/projects/myproject/index.ts', root directory '/user/username/projects/myproject/node_modules/@types'. ======== +Resolving with primary search path '/user/username/projects/myproject/node_modules/@types'. +Looking up in 'node_modules' folder, initial location '/user/username/projects/myproject'. +Found 'package.json' at '/user/username/projects/myproject/node_modules/pkg1/package.json'. +'package.json' does not have a 'typesVersions' field. +Saw non-matching condition 'import'. +Matched 'exports' condition 'require'. +Using 'exports' subpath '.' with target './require.js'. +File name '/user/username/projects/myproject/node_modules/pkg1/require.js' has a '.js' extension - stripping it. +File '/user/username/projects/myproject/node_modules/pkg1/require.d.ts' does not exist. +File '/user/username/projects/myproject/node_modules/@types/pkg1.d.ts' does not exist. +Directory '/user/username/projects/node_modules' does not exist, skipping all lookups in it. +Directory '/user/username/node_modules' does not exist, skipping all lookups in it. +Directory '/user/node_modules' does not exist, skipping all lookups in it. +Directory '/node_modules' does not exist, skipping all lookups in it. +======== Type reference directive 'pkg1' was not resolved. ======== +File '/user/username/projects/myproject/node_modules/pkg/package.json' exists according to earlier cached lookups. +======== Resolving type reference directive 'pkg2', containing file '/user/username/projects/myproject/__inferred type names__.ts', root directory '/user/username/projects/myproject/node_modules/@types'. ======== +Resolving with primary search path '/user/username/projects/myproject/node_modules/@types'. +File '/user/username/projects/myproject/node_modules/@types/pkg2/package.json' does not exist. +File '/user/username/projects/myproject/node_modules/@types/pkg2/index.d.ts' exist - use it as a name resolution result. +Resolving real path for '/user/username/projects/myproject/node_modules/@types/pkg2/index.d.ts', result '/user/username/projects/myproject/node_modules/@types/pkg2/index.d.ts'. +======== Type reference directive 'pkg2' was successfully resolved to '/user/username/projects/myproject/node_modules/@types/pkg2/index.d.ts', primary: true. ======== +File '/user/username/projects/myproject/node_modules/@types/pkg2/package.json' does not exist according to earlier cached lookups. +File '/user/username/projects/myproject/node_modules/@types/package.json' does not exist. +File '/user/username/projects/myproject/node_modules/package.json' does not exist. +File '/user/username/projects/myproject/package.json' does not exist according to earlier cached lookups. +File '/user/username/projects/package.json' does not exist according to earlier cached lookups. +File '/user/username/package.json' does not exist according to earlier cached lookups. +File '/user/package.json' does not exist according to earlier cached lookups. +File '/package.json' does not exist according to earlier cached lookups. +File '/a/lib/package.json' does not exist. +File '/a/package.json' does not exist. +File '/package.json' does not exist according to earlier cached lookups. +index.ts:2:23 - error TS2688: Cannot find type definition file for 'pkg1'. + +2 /// +   ~~~~ + +index.ts:3:41 - error TS2304: Cannot find name 'RequireInterface'. + +3 export interface LocalInterface extends RequireInterface {} +   ~~~~~~~~~~~~~~~~ + +[12:00:50 AM] Found 2 errors. Watching for file changes. + + + +Program root files: ["/user/username/projects/myproject/a.ts","/user/username/projects/myproject/index.ts"] +Program options: {"moduleResolution":3,"watch":true,"traceResolution":true,"configFilePath":"/user/username/projects/myproject/tsconfig.json"} +Program structureReused: Not +Program files:: +/a/lib/lib.d.ts +/user/username/projects/myproject/a.ts +/user/username/projects/myproject/node_modules/pkg/import.d.ts +/user/username/projects/myproject/index.ts +/user/username/projects/myproject/node_modules/@types/pkg2/index.d.ts + +Semantic diagnostics in builder refreshed for:: +/a/lib/lib.d.ts +/user/username/projects/myproject/a.ts +/user/username/projects/myproject/node_modules/pkg/import.d.ts +/user/username/projects/myproject/index.ts +/user/username/projects/myproject/node_modules/@types/pkg2/index.d.ts + +Shape signatures in builder refreshed for:: +/a/lib/lib.d.ts (used version) +/user/username/projects/myproject/a.ts (used version) +/user/username/projects/myproject/node_modules/pkg/import.d.ts (used version) +/user/username/projects/myproject/index.ts (used version) +/user/username/projects/myproject/node_modules/@types/pkg2/index.d.ts (used version) + +PolledWatches:: +/user/username/projects/myproject/package.json: + {"pollingInterval":2000} +/user/username/projects/package.json: + {"pollingInterval":2000} +/user/username/projects/myproject/node_modules/@types/pkg2/package.json: + {"pollingInterval":2000} +/user/username/projects/myproject/node_modules/@types/package.json: + {"pollingInterval":2000} +/user/username/projects/myproject/node_modules/package.json: + {"pollingInterval":2000} + +FsWatches:: +/user/username/projects/myproject/tsconfig.json: + {} +/user/username/projects/myproject/a.ts: + {} +/user/username/projects/myproject/index.ts: + {} +/user/username/projects/myproject/node_modules/pkg/import.d.ts: + {} +/user/username/projects/myproject/node_modules/@types/pkg2/index.d.ts: + {} +/a/lib/lib.d.ts: + {} +/user/username/projects/myproject/node_modules/pkg/package.json: + {} +/user/username/projects/myproject/node_modules/pkg1/package.json: + {} + +FsWatchesRecursive:: +/user/username/projects/myproject/node_modules: + {} +/user/username/projects/myproject/node_modules/@types: + {} +/user/username/projects/myproject: + {} + +exitCode:: ExitStatus.undefined + +//// [/user/username/projects/myproject/a.js] +"use strict"; +exports.__esModule = true; +exports.x = void 0; +exports.x = 10; + + +//// [/user/username/projects/myproject/index.js] +"use strict"; +exports.__esModule = true; +/// +/// + + + +Change:: modify aFile by adding import + +Input:: +//// [/user/username/projects/myproject/a.ts] +/// +export const x = 10; + + + +Output:: +>> Screen clear +[12:00:53 AM] File change detected. Starting incremental compilation... + +File '/a/lib/package.json' does not exist according to earlier cached lookups. +File '/a/package.json' does not exist according to earlier cached lookups. +File '/package.json' does not exist according to earlier cached lookups. +File '/user/username/projects/myproject/package.json' does not exist according to earlier cached lookups. +File '/user/username/projects/package.json' does not exist according to earlier cached lookups. +File '/user/username/package.json' does not exist according to earlier cached lookups. +File '/user/package.json' does not exist according to earlier cached lookups. +File '/package.json' does not exist according to earlier cached lookups. +File '/user/username/projects/myproject/node_modules/pkg/package.json' exists according to earlier cached lookups. +File '/user/username/projects/myproject/package.json' does not exist according to earlier cached lookups. +File '/user/username/projects/package.json' does not exist according to earlier cached lookups. +File '/user/username/package.json' does not exist according to earlier cached lookups. +File '/user/package.json' does not exist according to earlier cached lookups. +File '/package.json' does not exist according to earlier cached lookups. +File '/user/username/projects/myproject/node_modules/@types/pkg2/package.json' does not exist according to earlier cached lookups. +File '/user/username/projects/myproject/node_modules/@types/package.json' does not exist according to earlier cached lookups. +File '/user/username/projects/myproject/node_modules/package.json' does not exist according to earlier cached lookups. +File '/user/username/projects/myproject/package.json' does not exist according to earlier cached lookups. +File '/user/username/projects/package.json' does not exist according to earlier cached lookups. +File '/user/username/package.json' does not exist according to earlier cached lookups. +File '/user/package.json' does not exist according to earlier cached lookups. +File '/package.json' does not exist according to earlier cached lookups. +File '/user/username/projects/myproject/package.json' does not exist according to earlier cached lookups. +File '/user/username/projects/package.json' does not exist according to earlier cached lookups. +File '/user/username/package.json' does not exist according to earlier cached lookups. +File '/user/package.json' does not exist according to earlier cached lookups. +File '/package.json' does not exist according to earlier cached lookups. +======== Resolving type reference directive 'pkg', containing file '/user/username/projects/myproject/a.ts', root directory '/user/username/projects/myproject/node_modules/@types'. ======== +Resolving with primary search path '/user/username/projects/myproject/node_modules/@types'. +Looking up in 'node_modules' folder, initial location '/user/username/projects/myproject'. +File '/user/username/projects/myproject/node_modules/pkg/package.json' exists according to earlier cached lookups. +Matched 'exports' condition 'import'. +Using 'exports' subpath '.' with target './import.js'. +File name '/user/username/projects/myproject/node_modules/pkg/import.js' has a '.js' extension - stripping it. +File '/user/username/projects/myproject/node_modules/pkg/import.d.ts' exist - use it as a name resolution result. +Resolving real path for '/user/username/projects/myproject/node_modules/pkg/import.d.ts', result '/user/username/projects/myproject/node_modules/pkg/import.d.ts'. +======== Type reference directive 'pkg' was successfully resolved to '/user/username/projects/myproject/node_modules/pkg/import.d.ts' with Package ID 'pkg/import.d.ts@0.0.1', primary: false. ======== +File '/user/username/projects/myproject/node_modules/pkg/package.json' exists according to earlier cached lookups. +File '/user/username/projects/myproject/package.json' does not exist according to earlier cached lookups. +File '/user/username/projects/package.json' does not exist according to earlier cached lookups. +File '/user/username/package.json' does not exist according to earlier cached lookups. +File '/user/package.json' does not exist according to earlier cached lookups. +File '/package.json' does not exist according to earlier cached lookups. +Reusing resolution of type reference directive 'pkg' from '/user/username/projects/myproject/index.ts' of old program, it was successfully resolved to '/user/username/projects/myproject/node_modules/pkg/import.d.ts' with Package ID 'pkg/import.d.ts@0.0.1'. +Reusing resolution of type reference directive 'pkg1' from '/user/username/projects/myproject/index.ts' of old program, it was not resolved. +Reusing resolution of type reference directive 'pkg2' from '/user/username/projects/myproject/__inferred type names__.ts' of old program, it was successfully resolved to '/user/username/projects/myproject/node_modules/@types/pkg2/index.d.ts'. +File '/user/username/projects/myproject/node_modules/@types/pkg2/package.json' does not exist according to earlier cached lookups. +File '/user/username/projects/myproject/node_modules/@types/package.json' does not exist according to earlier cached lookups. +File '/user/username/projects/myproject/node_modules/package.json' does not exist according to earlier cached lookups. +File '/user/username/projects/myproject/package.json' does not exist according to earlier cached lookups. +File '/user/username/projects/package.json' does not exist according to earlier cached lookups. +File '/user/username/package.json' does not exist according to earlier cached lookups. +File '/user/package.json' does not exist according to earlier cached lookups. +File '/package.json' does not exist according to earlier cached lookups. +File '/a/lib/package.json' does not exist according to earlier cached lookups. +File '/a/package.json' does not exist according to earlier cached lookups. +File '/package.json' does not exist according to earlier cached lookups. +index.ts:2:23 - error TS2688: Cannot find type definition file for 'pkg1'. + +2 /// +   ~~~~ + +index.ts:3:41 - error TS2304: Cannot find name 'RequireInterface'. + +3 export interface LocalInterface extends RequireInterface {} +   ~~~~~~~~~~~~~~~~ + +[12:00:57 AM] Found 2 errors. Watching for file changes. + + + +Program root files: ["/user/username/projects/myproject/a.ts","/user/username/projects/myproject/index.ts"] +Program options: {"moduleResolution":3,"watch":true,"traceResolution":true,"configFilePath":"/user/username/projects/myproject/tsconfig.json"} +Program structureReused: SafeModules +Program files:: +/a/lib/lib.d.ts +/user/username/projects/myproject/node_modules/pkg/import.d.ts +/user/username/projects/myproject/a.ts +/user/username/projects/myproject/index.ts +/user/username/projects/myproject/node_modules/@types/pkg2/index.d.ts + +Semantic diagnostics in builder refreshed for:: +/user/username/projects/myproject/a.ts + +Shape signatures in builder refreshed for:: +/user/username/projects/myproject/a.ts (computed .d.ts) + +PolledWatches:: +/user/username/projects/myproject/package.json: + {"pollingInterval":2000} +/user/username/projects/package.json: + {"pollingInterval":2000} +/user/username/projects/myproject/node_modules/@types/pkg2/package.json: + {"pollingInterval":2000} +/user/username/projects/myproject/node_modules/@types/package.json: + {"pollingInterval":2000} +/user/username/projects/myproject/node_modules/package.json: + {"pollingInterval":2000} + +FsWatches:: +/user/username/projects/myproject/tsconfig.json: + {} +/user/username/projects/myproject/a.ts: + {} +/user/username/projects/myproject/index.ts: + {} +/user/username/projects/myproject/node_modules/pkg/import.d.ts: + {} +/user/username/projects/myproject/node_modules/@types/pkg2/index.d.ts: + {} +/a/lib/lib.d.ts: + {} +/user/username/projects/myproject/node_modules/pkg/package.json: + {} +/user/username/projects/myproject/node_modules/pkg1/package.json: + {} + +FsWatchesRecursive:: +/user/username/projects/myproject/node_modules: + {} +/user/username/projects/myproject/node_modules/@types: + {} +/user/username/projects/myproject: + {} + +exitCode:: ExitStatus.undefined + +//// [/user/username/projects/myproject/a.js] +"use strict"; +exports.__esModule = true; +exports.x = void 0; +/// +exports.x = 10; + +