diff --git a/src/compiler/moduleNameResolver.ts b/src/compiler/moduleNameResolver.ts index f978cf7ea0016..273f10f375f25 100644 --- a/src/compiler/moduleNameResolver.ts +++ b/src/compiler/moduleNameResolver.ts @@ -225,6 +225,7 @@ function createResolvedModuleWithFailedLookupLocationsHandlingSymlink( affectingLocations: string[], diagnostics: Diagnostic[], state: ModuleResolutionState, + cache: ModuleResolutionCache | NonRelativeModuleNameResolutionCache | undefined, legacyResult?: string, ): ResolvedModuleWithFailedLookupLocations { // If this is from node_modules for non relative name, always respect preserveSymlinks @@ -246,6 +247,7 @@ function createResolvedModuleWithFailedLookupLocationsHandlingSymlink( affectingLocations, diagnostics, state.resultFromCache, + cache, legacyResult, ); } @@ -257,13 +259,24 @@ function createResolvedModuleWithFailedLookupLocations( affectingLocations: string[], diagnostics: Diagnostic[], resultFromCache: ResolvedModuleWithFailedLookupLocations | undefined, + cache: ModuleResolutionCache | NonRelativeModuleNameResolutionCache | undefined, legacyResult?: string, ): ResolvedModuleWithFailedLookupLocations { if (resultFromCache) { - resultFromCache.failedLookupLocations = updateResolutionField(resultFromCache.failedLookupLocations, failedLookupLocations); - resultFromCache.affectingLocations = updateResolutionField(resultFromCache.affectingLocations, affectingLocations); - resultFromCache.resolutionDiagnostics = updateResolutionField(resultFromCache.resolutionDiagnostics, diagnostics); - return resultFromCache; + if (!cache?.isReadonly) { + resultFromCache.failedLookupLocations = updateResolutionField(resultFromCache.failedLookupLocations, failedLookupLocations); + resultFromCache.affectingLocations = updateResolutionField(resultFromCache.affectingLocations, affectingLocations); + resultFromCache.resolutionDiagnostics = updateResolutionField(resultFromCache.resolutionDiagnostics, diagnostics); + return resultFromCache; + } + else { + return { + ...resultFromCache, + failedLookupLocations: initializeResolutionFieldForReadonlyCache(resultFromCache.failedLookupLocations, failedLookupLocations), + affectingLocations: initializeResolutionFieldForReadonlyCache(resultFromCache.affectingLocations, affectingLocations), + resolutionDiagnostics: initializeResolutionFieldForReadonlyCache(resultFromCache.resolutionDiagnostics, diagnostics), + }; + } } return { resolvedModule: resolved && { @@ -291,6 +304,12 @@ export function updateResolutionField(to: T[] | undefined, value: T[] | undef return to; } +function initializeResolutionFieldForReadonlyCache(fromCache: T[] | undefined, value: T[]): T[] | undefined { + if (!fromCache?.length) return initializeResolutionField(value); + if (!value.length) return fromCache.slice(); + return [...fromCache, ...value]; +} + /** @internal */ export interface ModuleResolutionState { host: ModuleResolutionHost; @@ -612,10 +631,10 @@ export function resolveTypeReferenceDirective(typeReferenceDirectiveName: string affectingLocations: initializeResolutionField(affectingLocations), resolutionDiagnostics: initializeResolutionField(diagnostics), }; - if (containingDirectory) { - cache?.getOrCreateCacheForDirectory(containingDirectory, redirectedReference).set(typeReferenceDirectiveName, /*mode*/ resolutionMode, result); + if (containingDirectory && cache && !cache.isReadonly) { + cache.getOrCreateCacheForDirectory(containingDirectory, redirectedReference).set(typeReferenceDirectiveName, /*mode*/ resolutionMode, result); if (!isExternalModuleNameRelative(typeReferenceDirectiveName)) { - cache?.getOrCreateCacheForNonRelativeName(typeReferenceDirectiveName, resolutionMode, redirectedReference).set(containingDirectory, result); + cache.getOrCreateCacheForNonRelativeName(typeReferenceDirectiveName, resolutionMode, redirectedReference).set(containingDirectory, result); } } if (traceEnabled) traceResult(result); @@ -850,6 +869,8 @@ export interface PerDirectoryResolutionCache { * This updates the redirects map as well if needed so module resolutions are cached if they can across the projects */ update(options: CompilerOptions): void; + /** @internal */ directoryToModuleNameMap: CacheWithRedirects>; + /** @internal */ isReadonly?: boolean; } export interface NonRelativeNameResolutionCache { @@ -861,11 +882,13 @@ export interface NonRelativeNameResolutionCache { * This updates the redirects map as well if needed so module resolutions are cached if they can across the projects */ update(options: CompilerOptions): void; + /** @internal */ isReadonly?: boolean; } export interface PerNonRelativeNameCache { get(directory: string): T | undefined; set(directory: string, result: T): void; + /** @internal */ isReadonly?: boolean; } export interface ModuleResolutionCache extends PerDirectoryResolutionCache, NonRelativeModuleNameResolutionCache, PackageJsonInfoCache { @@ -889,6 +912,7 @@ export interface PackageJsonInfoCache { /** @internal */ entries(): [Path, PackageJsonInfo | boolean][]; /** @internal */ getInternalMap(): Map | undefined; clear(): void; + /** @internal */ isReadonly?: boolean; } export type PerModuleNameCache = PerNonRelativeNameCache; @@ -920,6 +944,7 @@ export interface CacheWithRedirects { getOrCreateMapOfCacheRedirects(redirectedReference: ResolvedProjectReference | undefined): Map; update(newOptions: CompilerOptions): void; clear(): void; + getOwnMap(): Map; } /** @internal */ @@ -936,6 +961,7 @@ export function createCacheWithRedirects(ownOptions: CompilerOptions | und getOrCreateMapOfCacheRedirects, update, clear, + getOwnMap: () => ownMap, }; function getMapOfCacheRedirects(redirectedReference: ResolvedProjectReference | undefined): Map | undefined { @@ -1042,6 +1068,7 @@ function createPerDirectoryResolutionCache( getOrCreateCacheForDirectory, clear, update, + directoryToModuleNameMap, }; function clear() { @@ -1426,10 +1453,12 @@ export function resolveModuleName(moduleName: string, containingFile: string, co if (result && result.resolvedModule) perfLogger?.logInfoEvent(`Module "${moduleName}" resolved to "${result.resolvedModule.resolvedFileName}"`); perfLogger?.logStopResolveModule((result && result.resolvedModule) ? "" + result.resolvedModule.resolvedFileName : "null"); - cache?.getOrCreateCacheForDirectory(containingDirectory, redirectedReference).set(moduleName, resolutionMode, result); - if (!isExternalModuleNameRelative(moduleName)) { - // put result in per-module name cache - cache?.getOrCreateCacheForNonRelativeName(moduleName, resolutionMode, redirectedReference).set(containingDirectory, result); + if (cache && !cache.isReadonly) { + cache.getOrCreateCacheForDirectory(containingDirectory, redirectedReference).set(moduleName, resolutionMode, result); + if (!isExternalModuleNameRelative(moduleName)) { + // put result in per-module name cache + cache.getOrCreateCacheForNonRelativeName(moduleName, resolutionMode, redirectedReference).set(containingDirectory, result); + } } } @@ -1850,6 +1879,7 @@ function nodeModuleNameResolverWorker( affectingLocations, diagnostics, state, + cache, legacyResult, ); @@ -2386,7 +2416,7 @@ export function getPackageJsonInfo(packageDirectory: string, onlyRecordFailures: trace(host, Diagnostics.Found_package_json_at_0, packageJsonPath); } const result: PackageJsonInfo = { packageDirectory, contents: { packageJsonContent, versionPaths: undefined, resolvedEntrypoints: undefined } }; - state.packageJsonInfoCache?.setPackageJsonInfo(packageJsonPath, result); + if (state.packageJsonInfoCache && !state.packageJsonInfoCache.isReadonly) state.packageJsonInfoCache.setPackageJsonInfo(packageJsonPath, result); state.affectingLocations?.push(packageJsonPath); return result; } @@ -2394,7 +2424,7 @@ export function getPackageJsonInfo(packageDirectory: string, onlyRecordFailures: if (directoryExists && traceEnabled) { trace(host, Diagnostics.File_0_does_not_exist, packageJsonPath); } - state.packageJsonInfoCache?.setPackageJsonInfo(packageJsonPath, directoryExists); + if (state.packageJsonInfoCache && !state.packageJsonInfoCache.isReadonly) state.packageJsonInfoCache.setPackageJsonInfo(packageJsonPath, directoryExists); // record package json as one of failed lookup locations - in the future if this file will appear it will invalidate resolution results state.failedLookupLocations?.push(packageJsonPath); } @@ -3178,6 +3208,7 @@ export function classicNameResolver(moduleName: string, containingFile: string, affectingLocations, diagnostics, state, + cache, ); function tryResolve(extensions: Extensions): SearchResult { @@ -3273,6 +3304,7 @@ export function loadModuleFromGlobalCache(moduleName: string, projectName: strin affectingLocations, diagnostics, state.resultFromCache, + /*cache*/ undefined, ); } diff --git a/src/compiler/resolutionCache.ts b/src/compiler/resolutionCache.ts index 35c03d294ed0d..6c150cb66ae0e 100644 --- a/src/compiler/resolutionCache.ts +++ b/src/compiler/resolutionCache.ts @@ -205,6 +205,18 @@ export interface ResolutionCacheHost extends MinimalResolutionCacheHost { getCurrentProgram(): Program | undefined; fileIsOpen(filePath: Path): boolean; onDiscoveredSymlink?(): void; + + // For incremental testing + beforeResolveSingleModuleNameWithoutWatching?( + moduleResolutionCache: ModuleResolutionCache, + ): any; + afterResolveSingleModuleNameWithoutWatching?( + moduleResolutionCache: ModuleResolutionCache, + moduleName: string, + containingFile: string, + result: ResolvedModuleWithFailedLookupLocations, + data: any, + ): any; } /** @internal */ @@ -439,6 +451,10 @@ export function getRootPathSplitLength(rootPath: Path) { return rootPath.split(directorySeparator).length - (hasTrailingDirectorySeparator(rootPath) ? 1 : 0); } +function getModuleResolutionHost(resolutionHost: ResolutionCacheHost) { + return resolutionHost.getCompilerHost?.() || resolutionHost; +} + /** @internal */ export function createModuleResolutionLoaderUsingGlobalCache( containingFile: string, @@ -471,7 +487,7 @@ function resolveModuleNameUsingGlobalCache( redirectedReference?: ResolvedProjectReference, mode?: ResolutionMode, ): ResolvedModuleWithFailedLookupLocations { - const host = resolutionHost.getCompilerHost?.() || resolutionHost; + const host = getModuleResolutionHost(resolutionHost); const primaryResult = ts_resolveModuleName(moduleName, containingFile, compilerOptions, host, moduleResolutionCache, redirectedReference, mode); // return result immediately only if global cache support is not enabled or if it is .ts, .tsx or .d.ts if (!resolutionHost.getGlobalCache) { @@ -686,6 +702,10 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD } function startCachingPerDirectoryResolution() { + moduleResolutionCache.isReadonly = undefined; + typeReferenceDirectiveResolutionCache.isReadonly = undefined; + libraryResolutionCache.isReadonly = undefined; + moduleResolutionCache.getPackageJsonInfoCache().isReadonly = undefined; moduleResolutionCache.clearAllExceptPackageJsonInfoCache(); typeReferenceDirectiveResolutionCache.clearAllExceptPackageJsonInfoCache(); libraryResolutionCache.clearAllExceptPackageJsonInfoCache(); @@ -740,6 +760,10 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD directoryWatchesOfFailedLookups.forEach(closeDirectoryWatchesOfFailedLookup); fileWatchesOfAffectingLocations.forEach(closeFileWatcherOfAffectingLocation); hasChangedAutomaticTypeDirectiveNames = false; + moduleResolutionCache.isReadonly = true; + typeReferenceDirectiveResolutionCache.isReadonly = true; + libraryResolutionCache.isReadonly = true; + moduleResolutionCache.getPackageJsonInfoCache().isReadonly = true; } function closeDirectoryWatchesOfFailedLookup(watcher: DirectoryWatchesOfFailedLookup, path: Path) { @@ -828,7 +852,7 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD } } else { - const host = resolutionHost.getCompilerHost?.() || resolutionHost; + const host = getModuleResolutionHost(resolutionHost); if (isTraceEnabled(options, host) && !seenNamesInFile.has(name, mode)) { const resolved = getResolutionWithResolvedFileName(resolution!); trace( @@ -912,7 +936,7 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD containingFile, redirectedReference, options, - resolutionHost.getCompilerHost?.() || resolutionHost, + getModuleResolutionHost(resolutionHost), typeReferenceDirectiveResolutionCache, ), getResolutionWithResolvedFileName: getResolvedTypeReferenceDirective, @@ -957,7 +981,7 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD options: CompilerOptions, libFileName: string, ) { - const host = resolutionHost.getCompilerHost?.() || resolutionHost; + const host = getModuleResolutionHost(resolutionHost); let resolution = resolvedLibraries?.get(libFileName); if (!resolution || resolution.isInvalidated) { const existingResolution = resolution; @@ -994,7 +1018,18 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD const resolutionsInFile = resolvedModuleNames.get(path); const resolution = resolutionsInFile?.get(moduleName, /*mode*/ undefined); if (resolution && !resolution.isInvalidated) return resolution; - return resolveModuleNameUsingGlobalCache(resolutionHost, moduleResolutionCache, moduleName, containingFile, resolutionHost.getCompilationSettings()); + const data = resolutionHost.beforeResolveSingleModuleNameWithoutWatching?.(moduleResolutionCache); + const host = getModuleResolutionHost(resolutionHost); + // We are not resolving d.ts so just normal resolution instead of doing resolution pass to global cache + const result = ts_resolveModuleName( + moduleName, + containingFile, + resolutionHost.getCompilationSettings(), + host, + moduleResolutionCache, + ); + resolutionHost.afterResolveSingleModuleNameWithoutWatching?.(moduleResolutionCache, moduleName, containingFile, result, data); + return result; } function isNodeModulesAtTypesDirectory(dirPath: Path) { diff --git a/src/harness/incrementalUtils.ts b/src/harness/incrementalUtils.ts index bb27be203e28a..742e0a88d8f66 100644 --- a/src/harness/incrementalUtils.ts +++ b/src/harness/incrementalUtils.ts @@ -264,7 +264,7 @@ export function verifyResolutionCache( resolutionToExpected.get(resolution)!.refCount === resolution.refCount, `${projectName}:: Expected Resolution ref count ${resolutionToExpected.get(resolution)!.refCount} but got ${resolution.refCount}`, ); - verifySet(resolutionToExpected.get(resolution)!.files, resolution.files, `Resolution files`); + verifySet(resolutionToExpected.get(resolution)!.files, resolution.files, `${projectName}:: Resolution files`); }); verifyMapOfResolutionSet(expected.resolvedFileToResolution, actual.resolvedFileToResolution, `resolvedFileToResolution`); verifyResolutionSet(expected.resolutionsWithFailedLookups, actual.resolutionsWithFailedLookups, `resolutionsWithFailedLookups`); @@ -273,6 +273,7 @@ export function verifyResolutionCache( verifyFileWatchesOfAffectingLocations(expected.fileWatchesOfAffectingLocations, actual.fileWatchesOfAffectingLocations); // Stop watching resolutions to verify everything gets closed. + expected.startCachingPerDirectoryResolution(); actual.resolvedModuleNames.forEach((_resolutions, path) => expected.removeResolutionsOfFile(path)); actual.resolvedTypeReferenceDirectives.forEach((_resolutions, path) => expected.removeResolutionsOfFile(path)); expected.finishCachingPerDirectoryResolution(/*newProgram*/ undefined, actualProgram); @@ -339,35 +340,6 @@ export function verifyResolutionCache( return expectedResolution; } - function verifyMap( - expected: Map | undefined, - actual: Map | undefined, - verifyValue: (expected: Expected | undefined, actual: Actual | undefined, key: string) => void, - caption: string, - ) { - expected?.forEach((expected, path) => verifyValue(expected, actual?.get(path), `${caption}:: ${path}`)); - actual?.forEach((actual, path) => verifyValue(expected?.get(path), actual, `${caption}:: ${path}`)); - } - - function verifySet( - expected: Set | undefined, - actual: Set | undefined, - caption: string, - ) { - expected?.forEach(expected => - ts.Debug.assert( - actual?.has(expected), - `${projectName}:: ${caption}:: Expected should be present in actual`, - ) - ); - actual?.forEach(actual => - ts.Debug.assert( - expected?.has(actual), - `${projectName}:: ${caption}:: Actual should be present in expected`, - ) - ); - } - function verifyMapOfResolutionSet( expected: Map> | undefined, actual: Map> | undefined, @@ -421,6 +393,35 @@ export function verifyResolutionCache( } } +function verifyMap( + expected: Map | undefined, + actual: Map | undefined, + verifyValue: (expected: Expected | undefined, actual: Actual | undefined, key: string) => void, + caption: string, +) { + expected?.forEach((expected, path) => verifyValue(expected, actual?.get(path), `${caption}:: ${path}`)); + actual?.forEach((actual, path) => verifyValue(expected?.get(path), actual, `${caption}:: ${path}`)); +} + +function verifySet( + expected: Set | undefined, + actual: Set | undefined, + caption: string, +) { + expected?.forEach(expected => + ts.Debug.assert( + actual?.has(expected), + `${caption}:: Expected should be present in actual`, + ) + ); + actual?.forEach(actual => + ts.Debug.assert( + expected?.has(actual), + `${caption}:: Actual should be present in expected`, + ) + ); +} + function verifyProgram(service: ts.server.ProjectService, project: ts.server.Project) { if (service.serverMode === ts.LanguageServiceMode.Syntactic) return; const options = project.getCompilerOptions(); @@ -510,6 +511,74 @@ function verifyProgram(service: ts.server.ProjectService, project: ts.server.Pro verifyResolutionCache(project.resolutionCache, project.getCurrentProgram()!, resolutionHostCacheHost, project.projectName); } +interface ResolveSingleModuleNameWithoutWatchingData { + resolutionToData: Map>; + packageJsonMap: Map | undefined; +} + +function beforeResolveSingleModuleNameWithoutWatching( + moduleResolutionCache: ts.ModuleResolutionCache, +): ResolveSingleModuleNameWithoutWatchingData { + const resolutionToData: ResolveSingleModuleNameWithoutWatchingData["resolutionToData"] = new Map(); + // Currently it doesnt matter if moduleResolutionCache itself changes or not so just verify resolutions: + moduleResolutionCache.directoryToModuleNameMap.getOwnMap().forEach(cache => { + cache.forEach(resolution => { + if (resolutionToData.has(resolution)) return; + resolutionToData.set(resolution, { + failedLookupLocations: resolution.failedLookupLocations?.slice(), + affectingLocations: resolution.affectingLocations?.slice(), + resolutionDiagnostics: resolution.resolutionDiagnostics?.slice(), + }); + }); + }); + + // We also care about package json info cache + const packageJsonMap = moduleResolutionCache.getPackageJsonInfoCache().getInternalMap(); + return { + resolutionToData, + packageJsonMap: packageJsonMap && new Map(packageJsonMap), + }; +} + +function afterResolveSingleModuleNameWithoutWatching( + moduleResolutionCache: ts.ModuleResolutionCache, + moduleName: string, + containingFile: string, + result: ts.ResolvedModuleWithFailedLookupLocations, + data: ResolveSingleModuleNameWithoutWatchingData, +) { + const existing = data.resolutionToData.get(result); + if (existing) { + verifyArrayLength(existing.failedLookupLocations, result.failedLookupLocations, "failedLookupLocations"); + verifyArrayLength(existing.affectingLocations, result.affectingLocations, "affectingLocations"); + verifyArrayLength(existing.resolutionDiagnostics, result.resolutionDiagnostics, "resolutionDiagnostics"); + } + + verifyMap( + data.packageJsonMap, + moduleResolutionCache.getPackageJsonInfoCache().getInternalMap(), + (expected, actual, caption) => ts.Debug.assert(expected === actual, caption), + `Expected packageJsonInfo to not change: ${moduleName} ${containingFile}`, + ); + + function verifyArrayLength(expected: T[] | undefined, actual: T[] | undefined, caption: string) { + ts.Debug.assert( + expected?.length === actual?.length, + `Expected ${caption} to not change: ${moduleName} ${containingFile}`, + () => + `Expected: ${JSON.stringify(expected, undefined, " ")}` + + `Actual: ${JSON.stringify(actual, undefined, " ")}`, + ); + } +} + +function onProjectCreation(project: ts.server.Project) { + if (project.projectKind !== ts.server.ProjectKind.Auxiliary) return; + + (project as ts.ResolutionCacheHost).beforeResolveSingleModuleNameWithoutWatching = beforeResolveSingleModuleNameWithoutWatching; + (project as ts.ResolutionCacheHost).afterResolveSingleModuleNameWithoutWatching = afterResolveSingleModuleNameWithoutWatching; +} + export interface IncrementalVerifierCallbacks { beforeVerification?(): any; afterVerification?(dataFromBefore: any): void; @@ -518,6 +587,7 @@ export interface IncrementalVerifierCallbacks { export function incrementalVerifier(service: ts.server.ProjectService) { service.verifyDocumentRegistry = withIncrementalVerifierCallbacks(service, verifyDocumentRegistry); service.verifyProgram = withIncrementalVerifierCallbacks(service, verifyProgram); + service.onProjectCreation = onProjectCreation; } function withIncrementalVerifierCallbacks( diff --git a/src/server/editorServices.ts b/src/server/editorServices.ts index 976ce0a27cb38..e365a1212bb73 100644 --- a/src/server/editorServices.ts +++ b/src/server/editorServices.ts @@ -140,6 +140,7 @@ import { ActionSet, asNormalizedPath, AutoImportProviderProject, + AuxiliaryProject, BeginEnablePluginResult, BeginInstallTypes, ConfiguredProject, @@ -153,6 +154,7 @@ import { hasNoTypeScriptSource, InferredProject, InvalidateCachedTypings, + isBackgroundProject, isConfiguredProject, isDynamicFileName, isInferredProject, @@ -1129,6 +1131,7 @@ export class ProjectService { /** @internal */ verifyDocumentRegistry = noop; /** @internal */ verifyProgram: (project: Project) => void = noop; + /** @internal */ onProjectCreation: (project: Project) => void = noop; readonly jsDocParsingMode: JSDocParsingMode | undefined; @@ -1325,15 +1328,14 @@ export class ProjectService { private delayUpdateProjectGraph(project: Project) { project.markAsDirty(); - if (project.projectKind !== ProjectKind.AutoImportProvider && project.projectKind !== ProjectKind.Auxiliary) { - const projectName = project.getProjectName(); - this.pendingProjectUpdates.set(projectName, project); - this.throttledOperations.schedule(projectName, /*delay*/ 250, () => { - if (this.pendingProjectUpdates.delete(projectName)) { - updateProjectIfDirty(project); - } - }); - } + if (isBackgroundProject(project)) return; + const projectName = project.getProjectName(); + this.pendingProjectUpdates.set(projectName, project); + this.throttledOperations.schedule(projectName, /*delay*/ 250, () => { + if (this.pendingProjectUpdates.delete(projectName)) { + updateProjectIfDirty(project); + } + }); } /** @internal */ @@ -2418,6 +2420,7 @@ export class ProjectService { private addFilesToNonInferredProject(project: ConfiguredProject | ExternalProject, files: T[], propertyReader: FilePropertyReader, typeAcquisition: TypeAcquisition): void { this.updateNonInferredProjectFiles(project, files, propertyReader); project.setTypeAcquisition(typeAcquisition); + project.markAsDirty(); } /** @internal */ @@ -2669,7 +2672,7 @@ export class ProjectService { configFileExistenceInfo.config.watchedDirectoriesStale = undefined; } - private updateNonInferredProjectFiles(project: Project, files: T[], propertyReader: FilePropertyReader) { + private updateNonInferredProjectFiles(project: Project, files: readonly T[], propertyReader: FilePropertyReader) { const projectRootFilesMap = project.getRootFilesMap(); const newRootScriptInfoMap = new Map(); @@ -2736,10 +2739,6 @@ export class ProjectService { } }); } - - // Just to ensure that even if root files dont change, the changes to the non root file are picked up, - // mark the project as dirty unconditionally - project.markAsDirty(); } private updateRootAndOptionsOfNonInferredProject(project: ExternalProject | ConfiguredProject, newUncheckedFiles: T[], propertyReader: FilePropertyReader, newOptions: CompilerOptions, newTypeAcquisition: TypeAcquisition, compileOnSave: boolean | undefined, watchOptions: WatchOptions | undefined) { @@ -2762,6 +2761,7 @@ export class ProjectService { const fileNames = this.reloadFileNamesOfParsedConfig(project.getConfigFilePath(), this.configFileExistenceInfoCache.get(project.canonicalConfigFilePath)!.config!); project.updateErrorOnNoInputFiles(fileNames); this.updateNonInferredProjectFiles(project, fileNames.concat(project.getExternalFiles(ProgramUpdateLevel.RootNamesAndUpdate)), fileNamePropertyReader); + project.markAsDirty(); return project.updateGraph(); } @@ -2782,7 +2782,7 @@ export class ProjectService { } /** @internal */ - setFileNamesOfAutoImportProviderProject(project: AutoImportProviderProject, fileNames: string[]) { + setFileNamesOfAutpImportProviderOrAuxillaryProject(project: AutoImportProviderProject | AuxiliaryProject, fileNames: readonly string[]) { this.updateNonInferredProjectFiles(project, fileNames, fileNamePropertyReader); } diff --git a/src/server/project.ts b/src/server/project.ts index 5293e06fa540b..e9538e411a018 100644 --- a/src/server/project.ts +++ b/src/server/project.ts @@ -579,9 +579,10 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo this.disableLanguageService(lastFileExceededProgramSize); } this.markAsDirty(); - if (projectKind !== ProjectKind.AutoImportProvider) { + if (!isBackgroundProject(this)) { this.projectService.pendingEnsureProjectForOpenFiles = true; } + this.projectService.onProjectCreation(this); } isKnownTypesPackageName(name: string): boolean { @@ -727,6 +728,7 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo return this.resolutionCache.resolveModuleNameLiterals(moduleLiterals, containingFile, redirectedReference, options, containingSourceFile, reusedNames); } + /** @internal */ getModuleResolutionCache(): ModuleResolutionCache | undefined { return this.resolutionCache.getModuleResolutionCache(); } @@ -2185,35 +2187,15 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo } /** @internal */ - getNoDtsResolutionProject(rootFileNames: readonly string[]): Project { + getNoDtsResolutionProject(rootFile: NormalizedPath): AuxiliaryProject { Debug.assert(this.projectService.serverMode === LanguageServiceMode.Semantic); if (!this.noDtsResolutionProject) { this.noDtsResolutionProject = new AuxiliaryProject(this.projectService, this.documentRegistry, this.getCompilerOptionsForNoDtsResolutionProject(), this.currentDirectory); } - - enumerateInsertsAndDeletes( - rootFileNames.map(toNormalizedPath), - this.noDtsResolutionProject.getRootFiles(), - getStringComparer(!this.useCaseSensitiveFileNames()), - pathToAdd => { - const info = this.projectService.getOrCreateScriptInfoNotOpenedByClient( - pathToAdd, - this.currentDirectory, - this.noDtsResolutionProject!.directoryStructureHost, - ); - if (info) { - this.noDtsResolutionProject!.addRoot(info, pathToAdd); - } - }, - pathToRemove => { - // It may be preferable to remove roots only once project grows to a certain size? - const info = this.noDtsResolutionProject!.getScriptInfo(pathToRemove); - if (info) { - this.noDtsResolutionProject!.removeRoot(info); - } - }, - ); - + if (this.noDtsResolutionProject.rootFile !== rootFile) { + this.projectService.setFileNamesOfAutpImportProviderOrAuxillaryProject(this.noDtsResolutionProject, [rootFile]); + this.noDtsResolutionProject.rootFile = rootFile; + } return this.noDtsResolutionProject; } @@ -2394,6 +2376,7 @@ export class InferredProject extends Project { /** @internal */ export class AuxiliaryProject extends Project { + /** @internal */ rootFile: NormalizedPath | undefined; constructor(projectService: ProjectService, documentRegistry: DocumentRegistry, compilerOptions: CompilerOptions, currentDirectory: string) { super(projectService.newAuxiliaryProjectName(), ProjectKind.Auxiliary, projectService, documentRegistry, /*hasExplicitListOfFiles*/ false, /*lastFileExceededProgramSize*/ undefined, compilerOptions, /*compileOnSaveEnabled*/ false, /*watchOptions*/ undefined, projectService.host, currentDirectory); } @@ -2601,7 +2584,7 @@ export class AutoImportProviderProject extends Project { ); } - this.projectService.setFileNamesOfAutoImportProviderProject(this, rootFileNames); + this.projectService.setFileNamesOfAutpImportProviderOrAuxillaryProject(this, rootFileNames); this.rootFileNames = rootFileNames; const oldProgram = this.getCurrentProgram(); const hasSameSetOfFiles = super.updateGraph(); @@ -3015,3 +2998,8 @@ export function isConfiguredProject(project: Project): project is ConfiguredProj export function isExternalProject(project: Project): project is ExternalProject { return project.projectKind === ProjectKind.External; } + +/**@internal */ +export function isBackgroundProject(project: Project): project is AutoImportProviderProject | AuxiliaryProject { + return project.projectKind === ProjectKind.AutoImportProvider || project.projectKind === ProjectKind.Auxiliary; +} diff --git a/src/server/scriptInfo.ts b/src/server/scriptInfo.ts index ca9f11d2e612a..d99a5e88eb06e 100644 --- a/src/server/scriptInfo.ts +++ b/src/server/scriptInfo.ts @@ -40,13 +40,13 @@ import { Errors, ExternalProject, InferredProject, + isBackgroundProject, isConfiguredProject, isExternalProject, isInferredProject, maxFileSize, NormalizedPath, Project, - ProjectKind, ScriptVersionCache, ServerHost, } from "./_namespaces/ts.server"; @@ -682,7 +682,7 @@ export class ScriptInfo { isContainedByBackgroundProject() { return some( this.containingProjects, - p => p.projectKind === ProjectKind.AutoImportProvider || p.projectKind === ProjectKind.Auxiliary, + isBackgroundProject, ); } @@ -730,7 +730,7 @@ export class ScriptInfo { * reported as the default project for a ScriptInfo. */ function ensurePrimaryProjectKind(project: Project | undefined) { - if (!project || project.projectKind === ProjectKind.AutoImportProvider || project.projectKind === ProjectKind.Auxiliary) { + if (!project || isBackgroundProject(project)) { return Errors.ThrowNoProject(); } return project; diff --git a/src/server/session.ts b/src/server/session.ts index 42d1f52685103..eb56d56b48296 100644 --- a/src/server/session.ts +++ b/src/server/session.ts @@ -139,6 +139,7 @@ import { WithMetadata, } from "./_namespaces/ts"; import { + AuxiliaryProject, CloseFileWatcherEvent, ConfigFileDiagEvent, ConfiguredProject, @@ -1542,7 +1543,7 @@ export class Session implements EventSender { if (needsJsResolution) { const definitionSet = createSet(d => d.textSpan.start, documentSpansEqual); definitions?.forEach(d => definitionSet.add(d)); - const noDtsProject = project.getNoDtsResolutionProject([file]); + const noDtsProject = project.getNoDtsResolutionProject(file); const ls = noDtsProject.getLanguageService(); const jsDefinitions = ls.getDefinitionAtPosition(file, position, /*searchOtherFilesOnly*/ true, /*stopAtAlias*/ false) ?.filter(d => toNormalizedPath(d.fileName) !== file); @@ -1564,8 +1565,16 @@ export class Session implements EventSender { const ambientCandidates = definitions.filter(d => toNormalizedPath(d.fileName) !== file && d.isAmbient); for (const candidate of some(ambientCandidates) ? ambientCandidates : getAmbientCandidatesByClimbingAccessChain()) { const fileNameToSearch = findImplementationFileFromDtsFileName(candidate.fileName, file, noDtsProject); - if (!fileNameToSearch || !ensureRoot(noDtsProject, fileNameToSearch)) { - continue; + if (!fileNameToSearch) continue; + const info = this.projectService.getOrCreateScriptInfoNotOpenedByClient( + fileNameToSearch, + noDtsProject.currentDirectory, + noDtsProject.directoryStructureHost, + ); + if (!info) continue; + if (!noDtsProject.containsScriptInfo(info)) { + noDtsProject.addRoot(info); + noDtsProject.updateGraph(); } const noDtsProgram = ls.getProgram()!; const fileToSearch = Debug.checkDefined(noDtsProgram.getSourceFile(fileNameToSearch)); @@ -1580,7 +1589,7 @@ export class Session implements EventSender { definitions = definitions.filter(d => !d.isAmbient && !d.failedAliasResolution); return this.mapDefinitionInfo(definitions, project); - function findImplementationFileFromDtsFileName(fileName: string, resolveFromFile: string, auxiliaryProject: Project) { + function findImplementationFileFromDtsFileName(fileName: string, resolveFromFile: string, auxiliaryProject: AuxiliaryProject) { const nodeModulesPathParts = getNodeModulePathParts(fileName); if (nodeModulesPathParts && fileName.lastIndexOf(nodeModulesPathPart) === nodeModulesPathParts.topLevelNodeModulesIndex) { // Second check ensures the fileName only contains one `/node_modules/`. If there's more than one I give up. @@ -1671,16 +1680,6 @@ export class Session implements EventSender { } }); } - - function ensureRoot(project: Project, fileName: string) { - const info = project.getScriptInfo(fileName); - if (!info) return false; - if (!project.containsScriptInfo(info)) { - project.addRoot(info); - project.updateGraph(); - } - return true; - } } private getEmitOutput(args: protocol.EmitOutputRequestArgs): EmitOutput | protocol.EmitOutput { diff --git a/src/testRunner/unittests/tsserver/auxiliaryProject.ts b/src/testRunner/unittests/tsserver/auxiliaryProject.ts index 65f99d06f0a29..78ee2341378a5 100644 --- a/src/testRunner/unittests/tsserver/auxiliaryProject.ts +++ b/src/testRunner/unittests/tsserver/auxiliaryProject.ts @@ -1,29 +1,34 @@ import * as ts from "../../_namespaces/ts"; +import { + dedent, +} from "../../_namespaces/Utils"; import { baselineTsserverLogs, createLoggerWithInMemoryLogs, createSession, openFilesForSession, + protocolFileLocationFromSubstring, } from "../helpers/tsserver"; import { createServerHost, File, + libFile, } from "../helpers/virtualFileSystemWithWatch"; -const aTs: File = { - path: "/a.ts", - content: `import { B } from "./b";`, -}; -const bDts: File = { - path: "/b.d.ts", - content: `export declare class B {}`, -}; -const bJs: File = { - path: "/b.js", - content: `export class B {}`, -}; -describe("unittests:: tsserver:: auxiliaryProject", () => { +describe("unittests:: tsserver:: auxiliaryProject::", () => { it("AuxiliaryProject does not remove scrips from InferredProject", () => { + const aTs: File = { + path: "/a.ts", + content: `import { B } from "./b";`, + }; + const bDts: File = { + path: "/b.d.ts", + content: `export declare class B {}`, + }; + const bJs: File = { + path: "/b.js", + content: `export class B {}`, + }; const host = createServerHost([aTs, bDts, bJs]); const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); const projectService = session.getProjectService(); @@ -33,8 +38,11 @@ describe("unittests:: tsserver:: auxiliaryProject", () => { const inferredProject = projectService.inferredProjects[0]; // getNoDtsResolutionProject will create an AuxiliaryProject with a.ts and b.js - const auxProject = inferredProject.getNoDtsResolutionProject([aTs.path]); - auxProject.updateGraph(); + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.FindSourceDefinition, + arguments: protocolFileLocationFromSubstring(aTs, "B"), + }); + const auxProject = inferredProject.getNoDtsResolutionProject(aTs.path as ts.server.NormalizedPath); // b.js ScriptInfo is now available because it's contained by the AuxiliaryProject. // The AuxiliaryProject should never be the default project for anything, so @@ -54,4 +62,126 @@ describe("unittests:: tsserver:: auxiliaryProject", () => { assert.equal(bJsScriptInfo.getDefaultProject().projectKind, ts.server.ProjectKind.Inferred); baselineTsserverLogs("auxiliaryProject", "does not remove scrips from InferredProject", session); }); + + it("file is added later through finding definition", () => { + const indexFile: File = { + path: "/user/users/projects/myproject/index.ts", + content: dedent` + import { command } from "yargs"; + command("foo", yargs => { + yargs.positional(); + }); + `, + }; + const host = createServerHost({ + "/user/users/projects/myproject/node_modules/@types/yargs/package.json": JSON.stringify( + { + name: "@types/yargs", + version: "1.0.0", + types: "./index.d.ts", + }, + undefined, + " ", + ), + "/user/users/projects/myproject/node_modules/@types/yargs/callback.d.ts": dedent` + export declare class Yargs { positional(): Yargs; } + `, + "/user/users/projects/myproject/node_modules/@types/yargs/index.d.ts": dedent` + import { Yargs } from "./callback"; + export declare function command(command: string, cb: (yargs: Yargs) => void): void; + `, + "/user/users/projects/myproject/node_modules/yargs/package.json": JSON.stringify( + { + name: "yargs", + version: "1.0.0", + main: "index.js", + }, + undefined, + " ", + ), + "/user/users/projects/myproject/node_modules/yargs/callback.js": dedent` + export class Yargs { positional() { } } + `, + "/user/users/projects/myproject/node_modules/yargs/index.js": dedent` + // Specifically didnt have ./callback import to ensure that resolving module sepcifier adds the file to project at later stage + export function command(cmd, cb) { cb(Yargs) } + `, + [indexFile.path]: indexFile.content, + [libFile.path]: libFile.content, + }); + const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); + openFilesForSession([indexFile], session); + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.FindSourceDefinition, + arguments: protocolFileLocationFromSubstring(indexFile, "positional"), + }); + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.FindSourceDefinition, + arguments: protocolFileLocationFromSubstring(indexFile, "positional"), + }); + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.FindSourceDefinition, + arguments: protocolFileLocationFromSubstring(indexFile, "command", { index: 1 }), + }); + baselineTsserverLogs("auxiliaryProject", "file is added later through finding definition", session); + }); + + it("resolution is reused from different folder", () => { + const indexFile: File = { + path: "/user/users/projects/myproject/some/index.ts", + content: dedent` + import { random } from "../folder/random"; + import { command } from "yargs"; + command("foo", yargs => { + yargs.positional(); + }); + `, + }; + const host = createServerHost({ + "/user/users/projects/myproject/node_modules/@types/yargs/package.json": JSON.stringify( + { + name: "@types/yargs", + version: "1.0.0", + types: "./index.d.ts", + }, + undefined, + " ", + ), + "/user/users/projects/myproject/node_modules/@types/yargs/callback.d.ts": dedent` + export declare class Yargs { positional(): Yargs; } + `, + "/user/users/projects/myproject/node_modules/@types/yargs/index.d.ts": dedent` + import { Yargs } from "./callback"; + export declare function command(command: string, cb: (yargs: Yargs) => void): void; + `, + "/user/users/projects/myproject/node_modules/yargs/package.json": JSON.stringify( + { + name: "yargs", + version: "1.0.0", + main: "index.js", + }, + undefined, + " ", + ), + "/user/users/projects/myproject/node_modules/yargs/callback.js": dedent` + export class Yargs { positional() { } } + `, + "/user/users/projects/myproject/node_modules/yargs/index.js": dedent` + // Specifically didnt have ./callback import to ensure that resolving module sepcifier adds the file to project at later stage + export function command(cmd, cb) { cb(Yargs) } + `, + "/user/users/projects/myproject/folder/random.ts": dedent` + import { Yargs } from "yargs/callback"; + `, + [indexFile.path]: indexFile.content, + [libFile.path]: libFile.content, + }); + const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); + openFilesForSession([indexFile], session); + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.FindSourceDefinition, + arguments: protocolFileLocationFromSubstring(indexFile, "positional"), + }); + baselineTsserverLogs("auxiliaryProject", "resolution is reused from different folder", session); + }); }); diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index 4b783a4b8dca4..51b0ea6c9f003 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -3354,7 +3354,6 @@ declare namespace ts { readFile(fileName: string): string | undefined; writeFile(fileName: string, content: string): void; fileExists(file: string): boolean; - getModuleResolutionCache(): ModuleResolutionCache | undefined; directoryExists(path: string): boolean; getDirectories(path: string): string[]; log(s: string): void; diff --git a/tests/baselines/reference/goToSource16_callbackParamDifferentFile.baseline.jsonc b/tests/baselines/reference/goToSource16_callbackParamDifferentFile.baseline.jsonc new file mode 100644 index 0000000000000..c619fc880e8c9 --- /dev/null +++ b/tests/baselines/reference/goToSource16_callbackParamDifferentFile.baseline.jsonc @@ -0,0 +1,20 @@ +// === goToSourceDefinition === +// === /node_modules/yargs/callback.js === +// export class Yargs { [|positional|]() { } } + +// === /index.ts === +// import { command } from "yargs"; +// command("foo", yargs => { +// yargs./*GOTO SOURCE DEF*/positional(); +// }); + + // === Details === + [ + { + "containerKind": "", + "containerName": "", + "kind": "", + "name": "", + "unverified": true + } + ] \ No newline at end of file diff --git a/tests/baselines/reference/goToSource17_AddsFileToProject.baseline.jsonc b/tests/baselines/reference/goToSource17_AddsFileToProject.baseline.jsonc new file mode 100644 index 0000000000000..c619fc880e8c9 --- /dev/null +++ b/tests/baselines/reference/goToSource17_AddsFileToProject.baseline.jsonc @@ -0,0 +1,20 @@ +// === goToSourceDefinition === +// === /node_modules/yargs/callback.js === +// export class Yargs { [|positional|]() { } } + +// === /index.ts === +// import { command } from "yargs"; +// command("foo", yargs => { +// yargs./*GOTO SOURCE DEF*/positional(); +// }); + + // === Details === + [ + { + "containerKind": "", + "containerName": "", + "kind": "", + "name": "", + "unverified": true + } + ] \ No newline at end of file diff --git a/tests/baselines/reference/goToSource18_reusedFromDifferentFolder.baseline.jsonc b/tests/baselines/reference/goToSource18_reusedFromDifferentFolder.baseline.jsonc new file mode 100644 index 0000000000000..b3386930c3368 --- /dev/null +++ b/tests/baselines/reference/goToSource18_reusedFromDifferentFolder.baseline.jsonc @@ -0,0 +1,21 @@ +// === goToSourceDefinition === +// === /node_modules/yargs/callback.js === +// export class Yargs { [|positional|]() { } } + +// === /some/index.ts === +// import { random } from "../folder/random"; +// import { command } from "yargs"; +// command("foo", yargs => { +// yargs./*GOTO SOURCE DEF*/positional(); +// }); + + // === Details === + [ + { + "containerKind": "", + "containerName": "", + "kind": "", + "name": "", + "unverified": true + } + ] \ No newline at end of file diff --git a/tests/baselines/reference/tsserver/auxiliaryProject/does-not-remove-scrips-from-InferredProject.js b/tests/baselines/reference/tsserver/auxiliaryProject/does-not-remove-scrips-from-InferredProject.js index 24c29ad25d746..9c4212b994878 100644 --- a/tests/baselines/reference/tsserver/auxiliaryProject/does-not-remove-scrips-from-InferredProject.js +++ b/tests/baselines/reference/tsserver/auxiliaryProject/does-not-remove-scrips-from-InferredProject.js @@ -59,6 +59,19 @@ FsWatches:: /b.d.ts: *new* {} +Before request + +Info seq [hh:mm:ss:mss] request: + { + "command": "findSourceDefinition", + "arguments": { + "file": "/a.ts", + "line": 1, + "offset": 10 + }, + "seq": 2, + "type": "request" + } Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /dev/null/auxiliaryProject1* Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /b.js 500 undefined WatchType: Closed Script info Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /dev/null/auxiliaryProject1* Version: 1 structureChanged: true structureIsReused:: Not Elapsed:: *ms @@ -74,7 +87,32 @@ Info seq [hh:mm:ss:mss] Files (2) Root file specified for compilation Info seq [hh:mm:ss:mss] ----------------------------------------------- -Before request +Info seq [hh:mm:ss:mss] response: + { + "response": [ + { + "file": "/b.js", + "start": { + "line": 1, + "offset": 14 + }, + "end": { + "line": 1, + "offset": 15 + }, + "contextStart": { + "line": 1, + "offset": 1 + }, + "contextEnd": { + "line": 1, + "offset": 18 + } + } + ], + "responseRequired": true + } +After request PolledWatches:: /a/lib/lib.d.ts: @@ -86,13 +124,15 @@ FsWatches:: /b.js: *new* {} +Before request + Info seq [hh:mm:ss:mss] request: { "command": "open", "arguments": { "file": "/b.js" }, - "seq": 2, + "seq": 3, "type": "request" } Info seq [hh:mm:ss:mss] FileWatcher:: Close:: WatchInfo: /b.js 500 undefined WatchType: Closed Script info diff --git a/tests/baselines/reference/tsserver/auxiliaryProject/file-is-added-later-through-finding-definition.js b/tests/baselines/reference/tsserver/auxiliaryProject/file-is-added-later-through-finding-definition.js new file mode 100644 index 0000000000000..d84a86dbc66c8 --- /dev/null +++ b/tests/baselines/reference/tsserver/auxiliaryProject/file-is-added-later-through-finding-definition.js @@ -0,0 +1,318 @@ +currentDirectory:: / useCaseSensitiveFileNames: false +Info seq [hh:mm:ss:mss] Provided types map file "/a/lib/typesMap.json" doesn't exist +Before request +//// [/user/users/projects/myproject/node_modules/@types/yargs/package.json] +{ + "name": "@types/yargs", + "version": "1.0.0", + "types": "./index.d.ts" +} + +//// [/user/users/projects/myproject/node_modules/@types/yargs/callback.d.ts] +export declare class Yargs { positional(): Yargs; } + + +//// [/user/users/projects/myproject/node_modules/@types/yargs/index.d.ts] + +import { Yargs } from "./callback"; +export declare function command(command: string, cb: (yargs: Yargs) => void): void; + + +//// [/user/users/projects/myproject/node_modules/yargs/package.json] +{ + "name": "yargs", + "version": "1.0.0", + "main": "index.js" +} + +//// [/user/users/projects/myproject/node_modules/yargs/callback.js] +export class Yargs { positional() { } } + + +//// [/user/users/projects/myproject/node_modules/yargs/index.js] +// Specifically didnt have ./callback import to ensure that resolving module sepcifier adds the file to project at later stage +export function command(cmd, cb) { cb(Yargs) } + + +//// [/user/users/projects/myproject/index.ts] +import { command } from "yargs"; +command("foo", yargs => { + yargs.positional(); +}); + + +//// [/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; } + + +Info seq [hh:mm:ss:mss] request: + { + "command": "open", + "arguments": { + "file": "/user/users/projects/myproject/index.ts" + }, + "seq": 1, + "type": "request" + } +Info seq [hh:mm:ss:mss] Search path: /user/users/projects/myproject +Info seq [hh:mm:ss:mss] For info: /user/users/projects/myproject/index.ts :: No config files found. +Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /user/users/projects/myproject/tsconfig.json 2000 undefined WatchType: Config file for the inferred project root +Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /user/users/projects/myproject/jsconfig.json 2000 undefined WatchType: Config file for the inferred project root +Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /dev/null/inferredProject1* +Info seq [hh:mm:ss:mss] DirectoryWatcher:: Added:: WatchInfo: /user/users/projects/myproject/node_modules 1 undefined WatchType: node_modules for closed script infos and package.jsons affecting module specifier cache +Info seq [hh:mm:ss:mss] Elapsed:: *ms DirectoryWatcher:: Added:: WatchInfo: /user/users/projects/myproject/node_modules 1 undefined WatchType: node_modules for closed script infos and package.jsons affecting module specifier cache +Info seq [hh:mm:ss:mss] DirectoryWatcher:: Added:: WatchInfo: /user/users/projects/myproject/node_modules 1 undefined Project: /dev/null/inferredProject1* WatchType: Failed Lookup Locations +Info seq [hh:mm:ss:mss] Elapsed:: *ms DirectoryWatcher:: Added:: WatchInfo: /user/users/projects/myproject/node_modules 1 undefined Project: /dev/null/inferredProject1* WatchType: Failed Lookup Locations +Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /user/users/projects/myproject/node_modules/@types/yargs/package.json 2000 undefined Project: /dev/null/inferredProject1* WatchType: File location affecting resolution +Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /a/lib/lib.d.ts 500 undefined WatchType: Closed Script info +Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /user/users/projects/myproject/node_modules/yargs/package.json 2000 undefined Project: /dev/null/inferredProject1* WatchType: File location affecting resolution +Info seq [hh:mm:ss:mss] DirectoryWatcher:: Added:: WatchInfo: /user/users/projects/myproject/node_modules/@types 1 undefined Project: /dev/null/inferredProject1* WatchType: Type roots +Info seq [hh:mm:ss:mss] Elapsed:: *ms DirectoryWatcher:: Added:: WatchInfo: /user/users/projects/myproject/node_modules/@types 1 undefined Project: /dev/null/inferredProject1* WatchType: Type roots +Info seq [hh:mm:ss:mss] DirectoryWatcher:: Added:: WatchInfo: /user/users/projects/node_modules/@types 1 undefined Project: /dev/null/inferredProject1* WatchType: Type roots +Info seq [hh:mm:ss:mss] Elapsed:: *ms DirectoryWatcher:: Added:: WatchInfo: /user/users/projects/node_modules/@types 1 undefined Project: /dev/null/inferredProject1* WatchType: Type roots +Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /dev/null/inferredProject1* Version: 1 structureChanged: true structureIsReused:: Not Elapsed:: *ms +Info seq [hh:mm:ss:mss] Project '/dev/null/inferredProject1*' (Inferred) +Info seq [hh:mm:ss:mss] Files (4) + /a/lib/lib.d.ts Text-1 "/// \ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array { length: number; [n: number]: T; }" + /user/users/projects/myproject/node_modules/@types/yargs/callback.d.ts Text-1 "export declare class Yargs { positional(): Yargs; }\n" + /user/users/projects/myproject/node_modules/@types/yargs/index.d.ts Text-1 "\nimport { Yargs } from \"./callback\";\nexport declare function command(command: string, cb: (yargs: Yargs) => void): void;\n" + /user/users/projects/myproject/index.ts SVC-1-0 "import { command } from \"yargs\";\ncommand(\"foo\", yargs => {\n yargs.positional();\n});\n" + + + ../../../../a/lib/lib.d.ts + Default library for target 'es5' + node_modules/@types/yargs/callback.d.ts + Imported via "./callback" from file 'node_modules/@types/yargs/index.d.ts' with packageId '@types/yargs/callback.d.ts@1.0.0' + node_modules/@types/yargs/index.d.ts + Imported via "yargs" from file 'index.ts' with packageId '@types/yargs/index.d.ts@1.0.0' + Entry point for implicit type library 'yargs' with packageId '@types/yargs/index.d.ts@1.0.0' + index.ts + Root file specified for compilation + +Info seq [hh:mm:ss:mss] ----------------------------------------------- +Info seq [hh:mm:ss:mss] Project '/dev/null/inferredProject1*' (Inferred) +Info seq [hh:mm:ss:mss] Files (4) + +Info seq [hh:mm:ss:mss] ----------------------------------------------- +Info seq [hh:mm:ss:mss] Open files: +Info seq [hh:mm:ss:mss] FileName: /user/users/projects/myproject/index.ts ProjectRootPath: undefined +Info seq [hh:mm:ss:mss] Projects: /dev/null/inferredProject1* +Info seq [hh:mm:ss:mss] response: + { + "responseRequired": false + } +After request + +PolledWatches:: +/user/users/projects/myproject/jsconfig.json: *new* + {"pollingInterval":2000} +/user/users/projects/myproject/tsconfig.json: *new* + {"pollingInterval":2000} +/user/users/projects/node_modules/@types: *new* + {"pollingInterval":500} + +FsWatches:: +/a/lib/lib.d.ts: *new* + {} +/user/users/projects/myproject/node_modules/@types/yargs/package.json: *new* + {} +/user/users/projects/myproject/node_modules/yargs/package.json: *new* + {} + +FsWatchesRecursive:: +/user/users/projects/myproject/node_modules: *new* + {} +/user/users/projects/myproject/node_modules/@types: *new* + {} + +Before request + +Info seq [hh:mm:ss:mss] request: + { + "command": "findSourceDefinition", + "arguments": { + "file": "/user/users/projects/myproject/index.ts", + "line": 3, + "offset": 11 + }, + "seq": 2, + "type": "request" + } +Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /dev/null/auxiliaryProject1* +Info seq [hh:mm:ss:mss] DirectoryWatcher:: Added:: WatchInfo: /user/users/projects/myproject/node_modules 1 undefined Project: /dev/null/auxiliaryProject1* WatchType: Failed Lookup Locations +Info seq [hh:mm:ss:mss] Elapsed:: *ms DirectoryWatcher:: Added:: WatchInfo: /user/users/projects/myproject/node_modules 1 undefined Project: /dev/null/auxiliaryProject1* WatchType: Failed Lookup Locations +Info seq [hh:mm:ss:mss] DirectoryWatcher:: Added:: WatchInfo: /user/users/projects/node_modules 1 undefined Project: /dev/null/auxiliaryProject1* WatchType: Failed Lookup Locations +Info seq [hh:mm:ss:mss] Elapsed:: *ms DirectoryWatcher:: Added:: WatchInfo: /user/users/projects/node_modules 1 undefined Project: /dev/null/auxiliaryProject1* WatchType: Failed Lookup Locations +Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /user/users/projects/myproject/node_modules/yargs/package.json 2000 undefined Project: /dev/null/auxiliaryProject1* WatchType: File location affecting resolution +Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /dev/null/auxiliaryProject1* Version: 1 structureChanged: true structureIsReused:: Not Elapsed:: *ms +Info seq [hh:mm:ss:mss] Project '/dev/null/auxiliaryProject1*' (Auxiliary) +Info seq [hh:mm:ss:mss] Files (2) + /user/users/projects/myproject/node_modules/yargs/index.js Text-1 "// Specifically didnt have ./callback import to ensure that resolving module sepcifier adds the file to project at later stage\nexport function command(cmd, cb) { cb(Yargs) }\n" + /user/users/projects/myproject/index.ts SVC-1-0 "import { command } from \"yargs\";\ncommand(\"foo\", yargs => {\n yargs.positional();\n});\n" + + + node_modules/yargs/index.js + Imported via "yargs" from file 'index.ts' with packageId 'yargs/index.js@1.0.0' + index.ts + Root file specified for compilation + +Info seq [hh:mm:ss:mss] ----------------------------------------------- +Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /dev/null/auxiliaryProject1* +Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /dev/null/auxiliaryProject1* Version: 2 structureChanged: true structureIsReused:: Not Elapsed:: *ms +Info seq [hh:mm:ss:mss] Project '/dev/null/auxiliaryProject1*' (Auxiliary) +Info seq [hh:mm:ss:mss] Files (3) + /user/users/projects/myproject/node_modules/yargs/index.js Text-1 "// Specifically didnt have ./callback import to ensure that resolving module sepcifier adds the file to project at later stage\nexport function command(cmd, cb) { cb(Yargs) }\n" + /user/users/projects/myproject/index.ts SVC-1-0 "import { command } from \"yargs\";\ncommand(\"foo\", yargs => {\n yargs.positional();\n});\n" + /user/users/projects/myproject/node_modules/yargs/callback.js Text-1 "export class Yargs { positional() { } }\n" + + + node_modules/yargs/index.js + Imported via "yargs" from file 'index.ts' with packageId 'yargs/index.js@1.0.0' + index.ts + Root file specified for compilation + node_modules/yargs/callback.js + Root file specified for compilation + +Info seq [hh:mm:ss:mss] ----------------------------------------------- +Info seq [hh:mm:ss:mss] response: + { + "response": [ + { + "file": "/user/users/projects/myproject/node_modules/yargs/callback.js", + "start": { + "line": 1, + "offset": 22 + }, + "end": { + "line": 1, + "offset": 32 + }, + "contextStart": { + "line": 1, + "offset": 22 + }, + "contextEnd": { + "line": 1, + "offset": 38 + }, + "unverified": true + } + ], + "responseRequired": true + } +After request + +PolledWatches:: +/user/users/projects/myproject/jsconfig.json: + {"pollingInterval":2000} +/user/users/projects/myproject/tsconfig.json: + {"pollingInterval":2000} +/user/users/projects/node_modules: *new* + {"pollingInterval":500} +/user/users/projects/node_modules/@types: + {"pollingInterval":500} + +FsWatches:: +/a/lib/lib.d.ts: + {} +/user/users/projects/myproject/node_modules/@types/yargs/package.json: + {} +/user/users/projects/myproject/node_modules/yargs/package.json: + {} + +FsWatchesRecursive:: +/user/users/projects/myproject/node_modules: + {} +/user/users/projects/myproject/node_modules/@types: + {} + +Before request + +Info seq [hh:mm:ss:mss] request: + { + "command": "findSourceDefinition", + "arguments": { + "file": "/user/users/projects/myproject/index.ts", + "line": 3, + "offset": 11 + }, + "seq": 3, + "type": "request" + } +Info seq [hh:mm:ss:mss] response: + { + "response": [ + { + "file": "/user/users/projects/myproject/node_modules/yargs/callback.js", + "start": { + "line": 1, + "offset": 22 + }, + "end": { + "line": 1, + "offset": 32 + }, + "contextStart": { + "line": 1, + "offset": 22 + }, + "contextEnd": { + "line": 1, + "offset": 38 + }, + "unverified": true + } + ], + "responseRequired": true + } +After request + +Before request + +Info seq [hh:mm:ss:mss] request: + { + "command": "findSourceDefinition", + "arguments": { + "file": "/user/users/projects/myproject/index.ts", + "line": 2, + "offset": 1 + }, + "seq": 4, + "type": "request" + } +Info seq [hh:mm:ss:mss] response: + { + "response": [ + { + "file": "/user/users/projects/myproject/node_modules/yargs/index.js", + "start": { + "line": 2, + "offset": 17 + }, + "end": { + "line": 2, + "offset": 24 + }, + "contextStart": { + "line": 2, + "offset": 1 + }, + "contextEnd": { + "line": 2, + "offset": 47 + } + } + ], + "responseRequired": true + } +After request diff --git a/tests/baselines/reference/tsserver/auxiliaryProject/resolution-is-reused-from-different-folder.js b/tests/baselines/reference/tsserver/auxiliaryProject/resolution-is-reused-from-different-folder.js new file mode 100644 index 0000000000000..536befc05979f --- /dev/null +++ b/tests/baselines/reference/tsserver/auxiliaryProject/resolution-is-reused-from-different-folder.js @@ -0,0 +1,272 @@ +currentDirectory:: / useCaseSensitiveFileNames: false +Info seq [hh:mm:ss:mss] Provided types map file "/a/lib/typesMap.json" doesn't exist +Before request +//// [/user/users/projects/myproject/node_modules/@types/yargs/package.json] +{ + "name": "@types/yargs", + "version": "1.0.0", + "types": "./index.d.ts" +} + +//// [/user/users/projects/myproject/node_modules/@types/yargs/callback.d.ts] +export declare class Yargs { positional(): Yargs; } + + +//// [/user/users/projects/myproject/node_modules/@types/yargs/index.d.ts] + +import { Yargs } from "./callback"; +export declare function command(command: string, cb: (yargs: Yargs) => void): void; + + +//// [/user/users/projects/myproject/node_modules/yargs/package.json] +{ + "name": "yargs", + "version": "1.0.0", + "main": "index.js" +} + +//// [/user/users/projects/myproject/node_modules/yargs/callback.js] +export class Yargs { positional() { } } + + +//// [/user/users/projects/myproject/node_modules/yargs/index.js] +// Specifically didnt have ./callback import to ensure that resolving module sepcifier adds the file to project at later stage +export function command(cmd, cb) { cb(Yargs) } + + +//// [/user/users/projects/myproject/folder/random.ts] +import { Yargs } from "yargs/callback"; + + +//// [/user/users/projects/myproject/some/index.ts] +import { random } from "../folder/random"; +import { command } from "yargs"; +command("foo", yargs => { + yargs.positional(); +}); + + +//// [/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; } + + +Info seq [hh:mm:ss:mss] request: + { + "command": "open", + "arguments": { + "file": "/user/users/projects/myproject/some/index.ts" + }, + "seq": 1, + "type": "request" + } +Info seq [hh:mm:ss:mss] Search path: /user/users/projects/myproject/some +Info seq [hh:mm:ss:mss] For info: /user/users/projects/myproject/some/index.ts :: No config files found. +Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /user/users/projects/myproject/some/tsconfig.json 2000 undefined WatchType: Config file for the inferred project root +Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /user/users/projects/myproject/some/jsconfig.json 2000 undefined WatchType: Config file for the inferred project root +Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /user/users/projects/myproject/tsconfig.json 2000 undefined WatchType: Config file for the inferred project root +Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /user/users/projects/myproject/jsconfig.json 2000 undefined WatchType: Config file for the inferred project root +Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /dev/null/inferredProject1* +Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /user/users/projects/myproject/folder/random.ts 500 undefined WatchType: Closed Script info +Info seq [hh:mm:ss:mss] DirectoryWatcher:: Added:: WatchInfo: /user/users/projects/myproject/node_modules 1 undefined WatchType: node_modules for closed script infos and package.jsons affecting module specifier cache +Info seq [hh:mm:ss:mss] Elapsed:: *ms DirectoryWatcher:: Added:: WatchInfo: /user/users/projects/myproject/node_modules 1 undefined WatchType: node_modules for closed script infos and package.jsons affecting module specifier cache +Info seq [hh:mm:ss:mss] DirectoryWatcher:: Added:: WatchInfo: /user/users/projects/myproject/node_modules 1 undefined Project: /dev/null/inferredProject1* WatchType: Failed Lookup Locations +Info seq [hh:mm:ss:mss] Elapsed:: *ms DirectoryWatcher:: Added:: WatchInfo: /user/users/projects/myproject/node_modules 1 undefined Project: /dev/null/inferredProject1* WatchType: Failed Lookup Locations +Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /user/users/projects/myproject/node_modules/@types/yargs/package.json 2000 undefined Project: /dev/null/inferredProject1* WatchType: File location affecting resolution +Info seq [hh:mm:ss:mss] DirectoryWatcher:: Added:: WatchInfo: /user/users/projects/myproject/some/node_modules 1 undefined Project: /dev/null/inferredProject1* WatchType: Failed Lookup Locations +Info seq [hh:mm:ss:mss] Elapsed:: *ms DirectoryWatcher:: Added:: WatchInfo: /user/users/projects/myproject/some/node_modules 1 undefined Project: /dev/null/inferredProject1* WatchType: Failed Lookup Locations +Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /a/lib/lib.d.ts 500 undefined WatchType: Closed Script info +Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /user/users/projects/myproject/node_modules/yargs/package.json 2000 undefined Project: /dev/null/inferredProject1* WatchType: File location affecting resolution +Info seq [hh:mm:ss:mss] DirectoryWatcher:: Added:: WatchInfo: /user/users/projects/myproject/folder/node_modules 1 undefined Project: /dev/null/inferredProject1* WatchType: Failed Lookup Locations +Info seq [hh:mm:ss:mss] Elapsed:: *ms DirectoryWatcher:: Added:: WatchInfo: /user/users/projects/myproject/folder/node_modules 1 undefined Project: /dev/null/inferredProject1* WatchType: Failed Lookup Locations +Info seq [hh:mm:ss:mss] DirectoryWatcher:: Added:: WatchInfo: /user/users/projects/myproject/some/node_modules/@types 1 undefined Project: /dev/null/inferredProject1* WatchType: Type roots +Info seq [hh:mm:ss:mss] Elapsed:: *ms DirectoryWatcher:: Added:: WatchInfo: /user/users/projects/myproject/some/node_modules/@types 1 undefined Project: /dev/null/inferredProject1* WatchType: Type roots +Info seq [hh:mm:ss:mss] DirectoryWatcher:: Added:: WatchInfo: /user/users/projects/myproject/node_modules/@types 1 undefined Project: /dev/null/inferredProject1* WatchType: Type roots +Info seq [hh:mm:ss:mss] Elapsed:: *ms DirectoryWatcher:: Added:: WatchInfo: /user/users/projects/myproject/node_modules/@types 1 undefined Project: /dev/null/inferredProject1* WatchType: Type roots +Info seq [hh:mm:ss:mss] DirectoryWatcher:: Added:: WatchInfo: /user/users/projects/node_modules/@types 1 undefined Project: /dev/null/inferredProject1* WatchType: Type roots +Info seq [hh:mm:ss:mss] Elapsed:: *ms DirectoryWatcher:: Added:: WatchInfo: /user/users/projects/node_modules/@types 1 undefined Project: /dev/null/inferredProject1* WatchType: Type roots +Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /dev/null/inferredProject1* Version: 1 structureChanged: true structureIsReused:: Not Elapsed:: *ms +Info seq [hh:mm:ss:mss] Project '/dev/null/inferredProject1*' (Inferred) +Info seq [hh:mm:ss:mss] Files (5) + /a/lib/lib.d.ts Text-1 "/// \ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array { length: number; [n: number]: T; }" + /user/users/projects/myproject/node_modules/@types/yargs/callback.d.ts Text-1 "export declare class Yargs { positional(): Yargs; }\n" + /user/users/projects/myproject/folder/random.ts Text-1 "import { Yargs } from \"yargs/callback\";\n" + /user/users/projects/myproject/node_modules/@types/yargs/index.d.ts Text-1 "\nimport { Yargs } from \"./callback\";\nexport declare function command(command: string, cb: (yargs: Yargs) => void): void;\n" + /user/users/projects/myproject/some/index.ts SVC-1-0 "import { random } from \"../folder/random\";\nimport { command } from \"yargs\";\ncommand(\"foo\", yargs => {\n yargs.positional();\n});\n" + + + ../../../../../a/lib/lib.d.ts + Default library for target 'es5' + ../node_modules/@types/yargs/callback.d.ts + Imported via "yargs/callback" from file '../folder/random.ts' with packageId '@types/yargs/callback.d.ts@1.0.0' + Imported via "./callback" from file '../node_modules/@types/yargs/index.d.ts' with packageId '@types/yargs/callback.d.ts@1.0.0' + ../folder/random.ts + Imported via "../folder/random" from file 'index.ts' + ../node_modules/@types/yargs/index.d.ts + Imported via "yargs" from file 'index.ts' with packageId '@types/yargs/index.d.ts@1.0.0' + Entry point for implicit type library 'yargs' with packageId '@types/yargs/index.d.ts@1.0.0' + index.ts + Root file specified for compilation + +Info seq [hh:mm:ss:mss] ----------------------------------------------- +Info seq [hh:mm:ss:mss] Project '/dev/null/inferredProject1*' (Inferred) +Info seq [hh:mm:ss:mss] Files (5) + +Info seq [hh:mm:ss:mss] ----------------------------------------------- +Info seq [hh:mm:ss:mss] Open files: +Info seq [hh:mm:ss:mss] FileName: /user/users/projects/myproject/some/index.ts ProjectRootPath: undefined +Info seq [hh:mm:ss:mss] Projects: /dev/null/inferredProject1* +Info seq [hh:mm:ss:mss] response: + { + "responseRequired": false + } +After request + +PolledWatches:: +/user/users/projects/myproject/folder/node_modules: *new* + {"pollingInterval":500} +/user/users/projects/myproject/jsconfig.json: *new* + {"pollingInterval":2000} +/user/users/projects/myproject/some/jsconfig.json: *new* + {"pollingInterval":2000} +/user/users/projects/myproject/some/node_modules: *new* + {"pollingInterval":500} +/user/users/projects/myproject/some/node_modules/@types: *new* + {"pollingInterval":500} +/user/users/projects/myproject/some/tsconfig.json: *new* + {"pollingInterval":2000} +/user/users/projects/myproject/tsconfig.json: *new* + {"pollingInterval":2000} +/user/users/projects/node_modules/@types: *new* + {"pollingInterval":500} + +FsWatches:: +/a/lib/lib.d.ts: *new* + {} +/user/users/projects/myproject/folder/random.ts: *new* + {} +/user/users/projects/myproject/node_modules/@types/yargs/package.json: *new* + {} +/user/users/projects/myproject/node_modules/yargs/package.json: *new* + {} + +FsWatchesRecursive:: +/user/users/projects/myproject/node_modules: *new* + {} +/user/users/projects/myproject/node_modules/@types: *new* + {} + +Before request + +Info seq [hh:mm:ss:mss] request: + { + "command": "findSourceDefinition", + "arguments": { + "file": "/user/users/projects/myproject/some/index.ts", + "line": 4, + "offset": 11 + }, + "seq": 2, + "type": "request" + } +Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /dev/null/auxiliaryProject1* +Info seq [hh:mm:ss:mss] DirectoryWatcher:: Added:: WatchInfo: /user/users/projects/myproject/some/node_modules 1 undefined Project: /dev/null/auxiliaryProject1* WatchType: Failed Lookup Locations +Info seq [hh:mm:ss:mss] Elapsed:: *ms DirectoryWatcher:: Added:: WatchInfo: /user/users/projects/myproject/some/node_modules 1 undefined Project: /dev/null/auxiliaryProject1* WatchType: Failed Lookup Locations +Info seq [hh:mm:ss:mss] DirectoryWatcher:: Added:: WatchInfo: /user/users/projects/myproject/node_modules 1 undefined Project: /dev/null/auxiliaryProject1* WatchType: Failed Lookup Locations +Info seq [hh:mm:ss:mss] Elapsed:: *ms DirectoryWatcher:: Added:: WatchInfo: /user/users/projects/myproject/node_modules 1 undefined Project: /dev/null/auxiliaryProject1* WatchType: Failed Lookup Locations +Info seq [hh:mm:ss:mss] DirectoryWatcher:: Added:: WatchInfo: /user/users/projects/node_modules 1 undefined Project: /dev/null/auxiliaryProject1* WatchType: Failed Lookup Locations +Info seq [hh:mm:ss:mss] Elapsed:: *ms DirectoryWatcher:: Added:: WatchInfo: /user/users/projects/node_modules 1 undefined Project: /dev/null/auxiliaryProject1* WatchType: Failed Lookup Locations +Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /user/users/projects/myproject/node_modules/yargs/package.json 2000 undefined Project: /dev/null/auxiliaryProject1* WatchType: File location affecting resolution +Info seq [hh:mm:ss:mss] DirectoryWatcher:: Added:: WatchInfo: /user/users/projects/myproject/folder/node_modules 1 undefined Project: /dev/null/auxiliaryProject1* WatchType: Failed Lookup Locations +Info seq [hh:mm:ss:mss] Elapsed:: *ms DirectoryWatcher:: Added:: WatchInfo: /user/users/projects/myproject/folder/node_modules 1 undefined Project: /dev/null/auxiliaryProject1* WatchType: Failed Lookup Locations +Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /dev/null/auxiliaryProject1* Version: 1 structureChanged: true structureIsReused:: Not Elapsed:: *ms +Info seq [hh:mm:ss:mss] Project '/dev/null/auxiliaryProject1*' (Auxiliary) +Info seq [hh:mm:ss:mss] Files (4) + /user/users/projects/myproject/node_modules/yargs/callback.js Text-1 "export class Yargs { positional() { } }\n" + /user/users/projects/myproject/folder/random.ts Text-1 "import { Yargs } from \"yargs/callback\";\n" + /user/users/projects/myproject/node_modules/yargs/index.js Text-1 "// Specifically didnt have ./callback import to ensure that resolving module sepcifier adds the file to project at later stage\nexport function command(cmd, cb) { cb(Yargs) }\n" + /user/users/projects/myproject/some/index.ts SVC-1-0 "import { random } from \"../folder/random\";\nimport { command } from \"yargs\";\ncommand(\"foo\", yargs => {\n yargs.positional();\n});\n" + + + ../node_modules/yargs/callback.js + Imported via "yargs/callback" from file '../folder/random.ts' with packageId 'yargs/callback.js@1.0.0' + ../folder/random.ts + Imported via "../folder/random" from file 'index.ts' + ../node_modules/yargs/index.js + Imported via "yargs" from file 'index.ts' with packageId 'yargs/index.js@1.0.0' + index.ts + Root file specified for compilation + +Info seq [hh:mm:ss:mss] ----------------------------------------------- +Info seq [hh:mm:ss:mss] response: + { + "response": [ + { + "file": "/user/users/projects/myproject/node_modules/yargs/callback.js", + "start": { + "line": 1, + "offset": 22 + }, + "end": { + "line": 1, + "offset": 32 + }, + "contextStart": { + "line": 1, + "offset": 22 + }, + "contextEnd": { + "line": 1, + "offset": 38 + }, + "unverified": true + } + ], + "responseRequired": true + } +After request + +PolledWatches:: +/user/users/projects/myproject/folder/node_modules: + {"pollingInterval":500} +/user/users/projects/myproject/jsconfig.json: + {"pollingInterval":2000} +/user/users/projects/myproject/some/jsconfig.json: + {"pollingInterval":2000} +/user/users/projects/myproject/some/node_modules: + {"pollingInterval":500} +/user/users/projects/myproject/some/node_modules/@types: + {"pollingInterval":500} +/user/users/projects/myproject/some/tsconfig.json: + {"pollingInterval":2000} +/user/users/projects/myproject/tsconfig.json: + {"pollingInterval":2000} +/user/users/projects/node_modules: *new* + {"pollingInterval":500} +/user/users/projects/node_modules/@types: + {"pollingInterval":500} + +FsWatches:: +/a/lib/lib.d.ts: + {} +/user/users/projects/myproject/folder/random.ts: + {} +/user/users/projects/myproject/node_modules/@types/yargs/package.json: + {} +/user/users/projects/myproject/node_modules/yargs/package.json: + {} + +FsWatchesRecursive:: +/user/users/projects/myproject/node_modules: + {} +/user/users/projects/myproject/node_modules/@types: + {} diff --git a/tests/cases/fourslash/server/goToSource16_callbackParamDifferentFile.ts b/tests/cases/fourslash/server/goToSource16_callbackParamDifferentFile.ts new file mode 100644 index 0000000000000..39f205c655172 --- /dev/null +++ b/tests/cases/fourslash/server/goToSource16_callbackParamDifferentFile.ts @@ -0,0 +1,41 @@ +/// + +// @moduleResolution: node + +// This is just modified repro to ensure we are resolving module specifier thats not already present in the file + +// @Filename: /node_modules/@types/yargs/package.json +//// { +//// "name": "@types/yargs", +//// "version": "1.0.0", +//// "types": "./index.d.ts" +//// } + +// @Filename: /node_modules/@types/yargs/callback.d.ts +//// export declare class Yargs { positional(): Yargs; } + +// @Filename: /node_modules/@types/yargs/index.d.ts +//// import { Yargs } from "./callback"; +//// export declare function command(command: string, cb: (yargs: Yargs) => void): void; + +// @Filename: /node_modules/yargs/package.json +//// { +//// "name": "yargs", +//// "version": "1.0.0", +//// "main": "index.js" +//// } + +// @Filename: /node_modules/yargs/callback.js +//// export class Yargs { positional() { } } + +// @Filename: /node_modules/yargs/index.js +//// import { Yargs } from "./callback"; +//// export function command(cmd, cb) { cb(Yargs) } + +// @Filename: /index.ts +//// import { command } from "yargs"; +//// command("foo", yargs => { +//// yargs.[|/*start*/positional|](); +//// }); + +verify.baselineGoToSourceDefinition("start"); diff --git a/tests/cases/fourslash/server/goToSource17_AddsFileToProject.ts b/tests/cases/fourslash/server/goToSource17_AddsFileToProject.ts new file mode 100644 index 0000000000000..f222452e89bfe --- /dev/null +++ b/tests/cases/fourslash/server/goToSource17_AddsFileToProject.ts @@ -0,0 +1,42 @@ +/// + +// @moduleResolution: node + +// This is just made up repro where the js file will be added to auxillary project because its not already part of the project +// Where in js file doesnt already have import to the corresponding js file hence will be added to project at later on stage + +// @Filename: /node_modules/@types/yargs/package.json +//// { +//// "name": "@types/yargs", +//// "version": "1.0.0", +//// "types": "./index.d.ts" +//// } + +// @Filename: /node_modules/@types/yargs/callback.d.ts +//// export declare class Yargs { positional(): Yargs; } + +// @Filename: /node_modules/@types/yargs/index.d.ts +//// import { Yargs } from "./callback"; +//// export declare function command(command: string, cb: (yargs: Yargs) => void): void; + +// @Filename: /node_modules/yargs/package.json +//// { +//// "name": "yargs", +//// "version": "1.0.0", +//// "main": "index.js" +//// } + +// @Filename: /node_modules/yargs/callback.js +//// export class Yargs { positional() { } } + +// @Filename: /node_modules/yargs/index.js +//// // Specifically didnt have ./callback import to ensure that resolving module sepcifier adds the file to project at later stage +//// export function command(cmd, cb) { cb(Yargs) } + +// @Filename: /index.ts +//// import { command } from "yargs"; +//// command("foo", yargs => { +//// yargs.[|/*start*/positional|](); +//// }); + +verify.baselineGoToSourceDefinition("start"); diff --git a/tests/cases/fourslash/server/goToSource18_reusedFromDifferentFolder.ts b/tests/cases/fourslash/server/goToSource18_reusedFromDifferentFolder.ts new file mode 100644 index 0000000000000..e5c4056317128 --- /dev/null +++ b/tests/cases/fourslash/server/goToSource18_reusedFromDifferentFolder.ts @@ -0,0 +1,46 @@ +/// + +// @moduleResolution: node + +// This is just made up repro where the js file will be added to auxillary project because its not already part of the project +// Where in js file doesnt already have import to the corresponding js file hence will be added to project at later on stage + +// @Filename: /node_modules/@types/yargs/package.json +//// { +//// "name": "@types/yargs", +//// "version": "1.0.0", +//// "types": "./index.d.ts" +//// } + +// @Filename: /node_modules/@types/yargs/callback.d.ts +//// export declare class Yargs { positional(): Yargs; } + +// @Filename: /node_modules/@types/yargs/index.d.ts +//// import { Yargs } from "./callback"; +//// export declare function command(command: string, cb: (yargs: Yargs) => void): void; + +// @Filename: /node_modules/yargs/package.json +//// { +//// "name": "yargs", +//// "version": "1.0.0", +//// "main": "index.js" +//// } + +// @Filename: /node_modules/yargs/callback.js +//// export class Yargs { positional() { } } + +// @Filename: /node_modules/yargs/index.js +//// // Specifically didnt have ./callback import to ensure that resolving module sepcifier adds the file to project at later stage +//// export function command(cmd, cb) { cb(Yargs) } + +// @Filename: /folder/random.ts +//// import { Yargs } from "yargs/callback"; + +// @Filename: /some/index.ts +//// import { random } from "../folder/random"; +//// import { command } from "yargs"; +//// command("foo", yargs => { +//// yargs.[|/*start*/positional|](); +//// }); + +verify.baselineGoToSourceDefinition("start");