mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-05-19 20:37:00 -05:00
Resolve only relative references in open files on syntax server (#39476)
* Resolve only relative references in open files on syntax server * Support resolving tripleslash references only in the open file * Apply suggestions from code review Co-authored-by: Daniel Rosenwasser <DanielRosenwasser@users.noreply.github.com> Co-authored-by: Daniel Rosenwasser <DanielRosenwasser@users.noreply.github.com>
This commit is contained in:
@@ -807,6 +807,8 @@ namespace ts {
|
||||
let mapFromFileToProjectReferenceRedirects: ESMap<Path, Path> | undefined;
|
||||
let mapFromToProjectReferenceRedirectSource: ESMap<Path, SourceOfProjectReferenceRedirect> | undefined;
|
||||
|
||||
let skippedTrippleSlashReferences: Set<Path> | undefined;
|
||||
|
||||
const useSourceOfProjectReferenceRedirect = !!host.useSourceOfProjectReferenceRedirect?.() &&
|
||||
!options.disableSourceOfProjectReferenceRedirect;
|
||||
const { onProgramCreateComplete, fileExists } = updateHostForUseSourceOfProjectReferenceRedirect({
|
||||
@@ -928,6 +930,7 @@ namespace ts {
|
||||
getSourceFiles: () => files,
|
||||
getMissingFilePaths: () => missingFilePaths!, // TODO: GH#18217
|
||||
getRefFileMap: () => refFileMap,
|
||||
getSkippedTrippleSlashReferences: () => skippedTrippleSlashReferences,
|
||||
getFilesByNameMap: () => filesByName,
|
||||
getCompilerOptions: () => options,
|
||||
getSyntacticDiagnostics,
|
||||
@@ -1269,6 +1272,7 @@ namespace ts {
|
||||
const oldSourceFiles = oldProgram.getSourceFiles();
|
||||
const enum SeenPackageName { Exists, Modified }
|
||||
const seenPackageNames = new Map<string, SeenPackageName>();
|
||||
const oldSkippedTrippleSlashReferences = oldProgram.getSkippedTrippleSlashReferences();
|
||||
|
||||
for (const oldSourceFile of oldSourceFiles) {
|
||||
let newSourceFile = host.getSourceFileByPath
|
||||
@@ -1341,6 +1345,11 @@ namespace ts {
|
||||
oldProgram.structureIsReused = StructureIsReused.SafeModules;
|
||||
}
|
||||
|
||||
if (oldSkippedTrippleSlashReferences?.has(oldSourceFile.path) && includeTripleslashReferencesFrom(newSourceFile)) {
|
||||
// tripleslash reference resolution is now allowed
|
||||
oldProgram.structureIsReused = StructureIsReused.SafeModules;
|
||||
}
|
||||
|
||||
// check imports and module augmentations
|
||||
collectExternalModuleReferences(newSourceFile);
|
||||
if (!arrayIsEqualTo(oldSourceFile.imports, newSourceFile.imports, moduleNameIsEqualTo)) {
|
||||
@@ -1428,6 +1437,7 @@ namespace ts {
|
||||
|
||||
missingFilePaths = oldProgram.getMissingFilePaths();
|
||||
refFileMap = oldProgram.getRefFileMap();
|
||||
skippedTrippleSlashReferences = oldSkippedTrippleSlashReferences;
|
||||
|
||||
// update fileName -> file mapping
|
||||
Debug.assert(newSourceFiles.length === oldProgram.getSourceFiles().length);
|
||||
@@ -2647,7 +2657,15 @@ namespace ts {
|
||||
return projectReferenceRedirects.get(projectReferencePath) || undefined;
|
||||
}
|
||||
|
||||
function includeTripleslashReferencesFrom(file: SourceFile) {
|
||||
return !host.includeTripleslashReferencesFrom || host.includeTripleslashReferencesFrom(file.originalFileName);
|
||||
}
|
||||
|
||||
function processReferencedFiles(file: SourceFile, isDefaultLib: boolean) {
|
||||
if (!includeTripleslashReferencesFrom(file)) {
|
||||
(skippedTrippleSlashReferences ||= new Set()).add(file.path);
|
||||
return;
|
||||
}
|
||||
forEach(file.referencedFiles, (ref, index) => {
|
||||
const referencedFileName = resolveTripleslashReference(ref.fileName, file.originalFileName);
|
||||
processSourceFile(
|
||||
|
||||
@@ -11,6 +11,7 @@ namespace ts {
|
||||
|
||||
invalidateResolutionsOfFailedLookupLocations(): boolean;
|
||||
invalidateResolutionOfFile(filePath: Path): void;
|
||||
removeRelativeNoResolveResolutionsOfFile(filePath: Path): boolean;
|
||||
removeResolutionsOfFile(filePath: Path): void;
|
||||
removeResolutionsFromProjectReferenceRedirects(filePath: Path): void;
|
||||
setFilesWithInvalidatedNonRelativeUnresolvedImports(filesWithUnresolvedImports: ESMap<Path, readonly string[]>): void;
|
||||
@@ -141,7 +142,21 @@ namespace ts {
|
||||
type GetResolutionWithResolvedFileName<T extends ResolutionWithFailedLookupLocations = ResolutionWithFailedLookupLocations, R extends ResolutionWithResolvedFileName = ResolutionWithResolvedFileName> =
|
||||
(resolution: T) => R | undefined;
|
||||
|
||||
export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootDirForResolution: string | undefined, logChangesWhenResolvingModule: boolean): ResolutionCache {
|
||||
export enum ResolutionKind {
|
||||
All,
|
||||
RelativeReferencesInOpenFileOnly
|
||||
}
|
||||
|
||||
const noResolveResolvedModule: ResolvedModuleWithFailedLookupLocations = {
|
||||
resolvedModule: undefined,
|
||||
failedLookupLocations: []
|
||||
};
|
||||
const noResolveResolvedTypeReferenceDirective: ResolvedTypeReferenceDirectiveWithFailedLookupLocations = {
|
||||
resolvedTypeReferenceDirective: undefined,
|
||||
failedLookupLocations: []
|
||||
};
|
||||
|
||||
export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootDirForResolution: string | undefined, resolutionKind: ResolutionKind, logChangesWhenResolvingModule: boolean): ResolutionCache {
|
||||
let filesWithChangedSetOfUnresolvedImports: Path[] | undefined;
|
||||
let filesWithInvalidatedResolutions: Set<Path> | undefined;
|
||||
let filesWithInvalidatedNonRelativeUnresolvedImports: ReadonlyESMap<Path, readonly string[]> | undefined;
|
||||
@@ -206,6 +221,7 @@ namespace ts {
|
||||
hasChangedAutomaticTypeDirectiveNames: () => hasChangedAutomaticTypeDirectiveNames,
|
||||
invalidateResolutionOfFile,
|
||||
invalidateResolutionsOfFailedLookupLocations,
|
||||
removeRelativeNoResolveResolutionsOfFile,
|
||||
setFilesWithInvalidatedNonRelativeUnresolvedImports,
|
||||
createHasInvalidatedResolution,
|
||||
updateTypeRootsWatch,
|
||||
@@ -341,11 +357,12 @@ namespace ts {
|
||||
shouldRetryResolution: (t: T) => boolean;
|
||||
reusedNames?: readonly string[];
|
||||
logChanges?: boolean;
|
||||
noResolveResolution: T;
|
||||
}
|
||||
function resolveNamesWithLocalCache<T extends ResolutionWithFailedLookupLocations, R extends ResolutionWithResolvedFileName>({
|
||||
names, containingFile, redirectedReference,
|
||||
cache, perDirectoryCacheWithRedirects,
|
||||
loader, getResolutionWithResolvedFileName,
|
||||
loader, getResolutionWithResolvedFileName, noResolveResolution,
|
||||
shouldRetryResolution, reusedNames, logChanges
|
||||
}: ResolveNamesWithLocalCacheInput<T, R>): (R | undefined)[] {
|
||||
const path = resolutionHost.toPath(containingFile);
|
||||
@@ -382,7 +399,10 @@ namespace ts {
|
||||
resolution = resolutionInDirectory;
|
||||
}
|
||||
else {
|
||||
resolution = loader(name, containingFile, compilerOptions, resolutionHost.getCompilerHost?.() || resolutionHost, redirectedReference);
|
||||
resolution = resolutionKind === ResolutionKind.All ||
|
||||
(isExternalModuleNameRelative(name) && resolutionHost.fileIsOpen(path)) ?
|
||||
loader(name, containingFile, compilerOptions, resolutionHost.getCompilerHost?.() || resolutionHost, redirectedReference) :
|
||||
noResolveResolution;
|
||||
perDirectoryResolution.set(name, resolution);
|
||||
}
|
||||
resolutionsInFile.set(name, resolution);
|
||||
@@ -441,6 +461,7 @@ namespace ts {
|
||||
loader: resolveTypeReferenceDirective,
|
||||
getResolutionWithResolvedFileName: getResolvedTypeReferenceDirective,
|
||||
shouldRetryResolution: resolution => resolution.resolvedTypeReferenceDirective === undefined,
|
||||
noResolveResolution: noResolveResolvedTypeReferenceDirective,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -455,7 +476,8 @@ namespace ts {
|
||||
getResolutionWithResolvedFileName: getResolvedModule,
|
||||
shouldRetryResolution: resolution => !resolution.resolvedModule || !resolutionExtensionIsTSOrJson(resolution.resolvedModule.extension),
|
||||
reusedNames,
|
||||
logChanges: logChangesWhenResolvingModule
|
||||
logChanges: logChangesWhenResolvingModule,
|
||||
noResolveResolution: noResolveResolvedModule,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -741,6 +763,31 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function removeRelativeNoResolveResolutionsOfFileFromCache<T extends ResolutionWithFailedLookupLocations>(
|
||||
cache: ESMap<Path, ESMap<string, T>>,
|
||||
filePath: Path,
|
||||
noResolveResolution: T,
|
||||
) {
|
||||
Debug.assert(resolutionKind === ResolutionKind.RelativeReferencesInOpenFileOnly);
|
||||
// Deleted file, stop watching failed lookups for all the resolutions in the file
|
||||
const resolutions = cache.get(filePath);
|
||||
if (!resolutions) return false;
|
||||
let invalidated = false;
|
||||
resolutions.forEach((resolution, name) => {
|
||||
if (resolution === noResolveResolution && isExternalModuleNameRelative(name)) {
|
||||
resolutions.delete(name);
|
||||
invalidated = true;
|
||||
}
|
||||
});
|
||||
return invalidated;
|
||||
}
|
||||
|
||||
function removeRelativeNoResolveResolutionsOfFile(filePath: Path) {
|
||||
let invalidated = removeRelativeNoResolveResolutionsOfFileFromCache(resolvedModuleNames, filePath, noResolveResolvedModule);
|
||||
invalidated = removeRelativeNoResolveResolutionsOfFileFromCache(resolvedTypeReferenceDirectives, filePath, noResolveResolvedTypeReferenceDirective) || invalidated;
|
||||
return invalidated;
|
||||
}
|
||||
|
||||
function setFilesWithInvalidatedNonRelativeUnresolvedImports(filesMap: ReadonlyESMap<Path, readonly string[]>) {
|
||||
Debug.assert(filesWithInvalidatedNonRelativeUnresolvedImports === filesMap || filesWithInvalidatedNonRelativeUnresolvedImports === undefined);
|
||||
filesWithInvalidatedNonRelativeUnresolvedImports = filesMap;
|
||||
|
||||
@@ -3687,6 +3687,8 @@ namespace ts {
|
||||
/* @internal */
|
||||
getRefFileMap(): MultiMap<Path, RefFile> | undefined;
|
||||
/* @internal */
|
||||
getSkippedTrippleSlashReferences(): Set<Path> | undefined;
|
||||
/* @internal */
|
||||
getFilesByNameMap(): ESMap<string, SourceFile | false | undefined>;
|
||||
|
||||
/**
|
||||
@@ -6227,6 +6229,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[], containingFile: string, redirectedReference: ResolvedProjectReference | undefined, options: CompilerOptions): (ResolvedTypeReferenceDirective | undefined)[];
|
||||
/* @internal */ includeTripleslashReferencesFrom?(containingFile: string): boolean;
|
||||
getEnvironmentVariable?(name: string): string | undefined;
|
||||
/* @internal */ onReleaseOldSourceFile?(oldSourceFile: SourceFile, oldOptions: CompilerOptions, hasSourceFileByPath: boolean): void;
|
||||
/* @internal */ hasInvalidatedResolution?: HasInvalidatedResolution;
|
||||
|
||||
@@ -320,6 +320,7 @@ namespace ts {
|
||||
configFileName ?
|
||||
getDirectoryPath(getNormalizedAbsolutePath(configFileName, currentDirectory)) :
|
||||
currentDirectory,
|
||||
ResolutionKind.All,
|
||||
/*logChangesWhenResolvingModule*/ false
|
||||
);
|
||||
// Resolve module using host module resolution strategy if provided otherwise use resolution cache to resolve module names
|
||||
|
||||
@@ -2967,7 +2967,15 @@ namespace ts.server {
|
||||
let project: ConfiguredProject | ExternalProject | undefined = this.findExternalProjectContainingOpenScriptInfo(info);
|
||||
let defaultConfigProject: ConfiguredProject | undefined;
|
||||
let retainProjects: ConfiguredProject[] | ConfiguredProject | undefined;
|
||||
if (!project && !this.syntaxOnly) { // Checking syntaxOnly is an optimization
|
||||
if (this.syntaxOnly) {
|
||||
// Invalidate resolutions in the file since this file is now open
|
||||
info.containingProjects.forEach(project => {
|
||||
if (project.resolutionCache.removeRelativeNoResolveResolutionsOfFile(info.path)) {
|
||||
project.markAsDirty();
|
||||
}
|
||||
});
|
||||
}
|
||||
else if (!project) { // Checking syntaxOnly is an optimization
|
||||
configFileName = this.getConfigFileNameForFile(info);
|
||||
if (configFileName) {
|
||||
project = this.findConfiguredProjectByProjectName(configFileName);
|
||||
@@ -3047,6 +3055,10 @@ namespace ts.server {
|
||||
Debug.assert(this.openFiles.has(info.path));
|
||||
this.assignOrphanScriptInfoToInferredProject(info, this.openFiles.get(info.path));
|
||||
}
|
||||
else if (this.syntaxOnly && info.cacheSourceFile?.sourceFile.referencedFiles.length) {
|
||||
// This file was just opened and references in this file will previously not been resolved so schedule update
|
||||
info.containingProjects.forEach(project => project.markAsDirty());
|
||||
}
|
||||
Debug.assert(!info.isOrphan());
|
||||
return { configFileName, configFileErrors, retainProjects };
|
||||
}
|
||||
|
||||
@@ -281,7 +281,6 @@ namespace ts.server {
|
||||
|
||||
this.languageServiceEnabled = true;
|
||||
if (projectService.syntaxOnly) {
|
||||
this.compilerOptions.noResolve = true;
|
||||
this.compilerOptions.types = [];
|
||||
}
|
||||
|
||||
@@ -296,7 +295,12 @@ namespace ts.server {
|
||||
this.realpath = maybeBind(host, host.realpath);
|
||||
|
||||
// Use the current directory as resolution root only if the project created using current directory string
|
||||
this.resolutionCache = createResolutionCache(this, currentDirectory && this.currentDirectory, /*logChangesWhenResolvingModule*/ true);
|
||||
this.resolutionCache = createResolutionCache(
|
||||
this,
|
||||
currentDirectory && this.currentDirectory,
|
||||
projectService.syntaxOnly ? ResolutionKind.RelativeReferencesInOpenFileOnly : ResolutionKind.All,
|
||||
/*logChangesWhenResolvingModule*/ true
|
||||
);
|
||||
this.languageService = createLanguageService(this, this.documentRegistry, this.projectService.syntaxOnly);
|
||||
if (lastFileExceededProgramSize) {
|
||||
this.disableLanguageService(lastFileExceededProgramSize);
|
||||
@@ -450,6 +454,11 @@ namespace ts.server {
|
||||
return this.resolutionCache.resolveTypeReferenceDirectives(typeDirectiveNames, containingFile, redirectedReference);
|
||||
}
|
||||
|
||||
/*@internal*/
|
||||
includeTripleslashReferencesFrom(containingFile: string) {
|
||||
return !this.projectService.syntaxOnly || this.fileIsOpen(this.toPath(containingFile));
|
||||
}
|
||||
|
||||
directoryExists(path: string): boolean {
|
||||
return this.directoryStructureHost.directoryExists!(path); // TODO: GH#18217
|
||||
}
|
||||
|
||||
@@ -1296,7 +1296,7 @@ namespace ts {
|
||||
getCurrentDirectory: () => currentDirectory,
|
||||
fileExists,
|
||||
readFile,
|
||||
realpath: host.realpath && (path => host.realpath!(path)),
|
||||
realpath: maybeBind(host, host.realpath),
|
||||
directoryExists: directoryName => {
|
||||
return directoryProbablyExists(directoryName, host);
|
||||
},
|
||||
@@ -1309,21 +1309,13 @@ namespace ts {
|
||||
},
|
||||
onReleaseOldSourceFile,
|
||||
hasInvalidatedResolution,
|
||||
hasChangedAutomaticTypeDirectiveNames
|
||||
hasChangedAutomaticTypeDirectiveNames,
|
||||
includeTripleslashReferencesFrom: maybeBind(host, host.includeTripleslashReferencesFrom),
|
||||
trace: maybeBind(host, host.trace),
|
||||
resolveModuleNames: maybeBind(host, host.resolveModuleNames),
|
||||
resolveTypeReferenceDirectives: maybeBind(host, host.resolveTypeReferenceDirectives),
|
||||
useSourceOfProjectReferenceRedirect: maybeBind(host, host.useSourceOfProjectReferenceRedirect),
|
||||
};
|
||||
if (host.trace) {
|
||||
compilerHost.trace = message => host.trace!(message);
|
||||
}
|
||||
|
||||
if (host.resolveModuleNames) {
|
||||
compilerHost.resolveModuleNames = (...args) => host.resolveModuleNames!(...args);
|
||||
}
|
||||
if (host.resolveTypeReferenceDirectives) {
|
||||
compilerHost.resolveTypeReferenceDirectives = (...args) => host.resolveTypeReferenceDirectives!(...args);
|
||||
}
|
||||
if (host.useSourceOfProjectReferenceRedirect) {
|
||||
compilerHost.useSourceOfProjectReferenceRedirect = () => host.useSourceOfProjectReferenceRedirect!();
|
||||
}
|
||||
host.setCompilerHost?.(compilerHost);
|
||||
|
||||
const documentRegistryBucketKey = documentRegistry.getKeyForCompilationSettings(newSettings);
|
||||
|
||||
@@ -266,6 +266,7 @@ namespace ts {
|
||||
resolveModuleNames?(moduleNames: string[], containingFile: string, reusedNames: string[] | undefined, redirectedReference: ResolvedProjectReference | undefined, options: CompilerOptions): (ResolvedModule | undefined)[];
|
||||
getResolvedModuleWithFailedLookupLocationsFromCache?(modulename: string, containingFile: string): ResolvedModuleWithFailedLookupLocations | undefined;
|
||||
resolveTypeReferenceDirectives?(typeDirectiveNames: string[], containingFile: string, redirectedReference: ResolvedProjectReference | undefined, options: CompilerOptions): (ResolvedTypeReferenceDirective | undefined)[];
|
||||
/* @internal */ includeTripleslashReferencesFrom?(containingFile: string): boolean;
|
||||
/* @internal */ hasInvalidatedResolution?: HasInvalidatedResolution;
|
||||
/* @internal */ hasChangedAutomaticTypeDirectiveNames?: HasChangedAutomaticTypeDirectiveNames;
|
||||
/* @internal */
|
||||
|
||||
@@ -3,35 +3,66 @@ namespace ts.projectSystem {
|
||||
function setup() {
|
||||
const file1: File = {
|
||||
path: `${tscWatch.projectRoot}/a.ts`,
|
||||
content: `import { y } from "./b";
|
||||
content: `import { y, cc } from "./b";
|
||||
import { something } from "something";
|
||||
class c { prop = "hello"; foo() { return this.prop; } }`
|
||||
};
|
||||
const file2: File = {
|
||||
path: `${tscWatch.projectRoot}/b.ts`,
|
||||
content: "export const y = 10;"
|
||||
content: `export { cc } from "./c";
|
||||
import { something } from "something";
|
||||
export const y = 10;`
|
||||
};
|
||||
const file3: File = {
|
||||
path: `${tscWatch.projectRoot}/c.ts`,
|
||||
content: `export const cc = 10;`
|
||||
};
|
||||
const something: File = {
|
||||
path: `${tscWatch.projectRoot}/node_modules/something/index.d.ts`,
|
||||
content: "export const something = 10;"
|
||||
};
|
||||
const configFile: File = {
|
||||
path: `${tscWatch.projectRoot}/tsconfig.json`,
|
||||
content: "{}"
|
||||
};
|
||||
const host = createServerHost([file1, file2, libFile, configFile]);
|
||||
const host = createServerHost([file1, file2, file3, something, libFile, configFile]);
|
||||
const session = createSession(host, { syntaxOnly: true, useSingleInferredProject: true });
|
||||
return { host, session, file1, file2, configFile };
|
||||
return { host, session, file1, file2, file3, something, configFile };
|
||||
}
|
||||
|
||||
it("open files are added to inferred project even if config file is present and semantic operations succeed", () => {
|
||||
const { host, session, file1, file2 } = setup();
|
||||
const { host, session, file1, file2, file3, something } = setup();
|
||||
const service = session.getProjectService();
|
||||
openFilesForSession([file1], session);
|
||||
checkNumberOfProjects(service, { inferredProjects: 1 });
|
||||
const project = service.inferredProjects[0];
|
||||
checkProjectActualFiles(project, [libFile.path, file1.path]); // Import is not resolved
|
||||
checkProjectActualFiles(project, [libFile.path, file1.path, file2.path]); // Relative import from open file is resolves but not non relative
|
||||
verifyCompletions();
|
||||
verifyGoToDefToB();
|
||||
|
||||
openFilesForSession([file2], session);
|
||||
checkNumberOfProjects(service, { inferredProjects: 1 });
|
||||
checkProjectActualFiles(project, [libFile.path, file1.path, file2.path]);
|
||||
checkProjectActualFiles(project, [libFile.path, file1.path, file2.path, file3.path]);
|
||||
verifyCompletions();
|
||||
verifyGoToDefToB();
|
||||
verifyGoToDefToC();
|
||||
|
||||
openFilesForSession([file3], session);
|
||||
checkNumberOfProjects(service, { inferredProjects: 1 });
|
||||
checkProjectActualFiles(project, [libFile.path, file1.path, file2.path, file3.path]);
|
||||
|
||||
openFilesForSession([something], session);
|
||||
checkNumberOfProjects(service, { inferredProjects: 1 });
|
||||
checkProjectActualFiles(project, [libFile.path, file1.path, file2.path, file3.path, something.path]);
|
||||
|
||||
// Close open files and verify resolutions
|
||||
closeFilesForSession([file3], session);
|
||||
checkNumberOfProjects(service, { inferredProjects: 1 });
|
||||
checkProjectActualFiles(project, [libFile.path, file1.path, file2.path, file3.path, something.path]);
|
||||
|
||||
closeFilesForSession([file2], session);
|
||||
checkNumberOfProjects(service, { inferredProjects: 1 });
|
||||
checkProjectActualFiles(project, [libFile.path, file1.path, file2.path, file3.path, something.path]);
|
||||
|
||||
function verifyCompletions() {
|
||||
assert.isTrue(project.languageServiceEnabled);
|
||||
@@ -62,6 +93,34 @@ class c { prop = "hello"; foo() { return this.prop; } }`
|
||||
source: undefined
|
||||
};
|
||||
}
|
||||
|
||||
function verifyGoToDefToB() {
|
||||
const response = session.executeCommandSeq<protocol.DefinitionAndBoundSpanRequest>({
|
||||
command: protocol.CommandTypes.DefinitionAndBoundSpan,
|
||||
arguments: protocolFileLocationFromSubstring(file1, "y")
|
||||
}).response as protocol.DefinitionInfoAndBoundSpan;
|
||||
assert.deepEqual(response, {
|
||||
definitions: [{
|
||||
file: file2.path,
|
||||
...protocolTextSpanWithContextFromSubstring({ fileText: file2.content, text: "y", contextText: "export const y = 10;" })
|
||||
}],
|
||||
textSpan: protocolTextSpanWithContextFromSubstring({ fileText: file1.content, text: "y" })
|
||||
});
|
||||
}
|
||||
|
||||
function verifyGoToDefToC() {
|
||||
const response = session.executeCommandSeq<protocol.DefinitionAndBoundSpanRequest>({
|
||||
command: protocol.CommandTypes.DefinitionAndBoundSpan,
|
||||
arguments: protocolFileLocationFromSubstring(file1, "cc")
|
||||
}).response as protocol.DefinitionInfoAndBoundSpan;
|
||||
assert.deepEqual(response, {
|
||||
definitions: [{
|
||||
file: file3.path,
|
||||
...protocolTextSpanWithContextFromSubstring({ fileText: file3.content, text: "cc", contextText: "export const cc = 10;" })
|
||||
}],
|
||||
textSpan: protocolTextSpanWithContextFromSubstring({ fileText: file1.content, text: "cc" })
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
it("throws on unsupported commands", () => {
|
||||
@@ -97,7 +156,7 @@ class c { prop = "hello"; foo() { return this.prop; } }`
|
||||
});
|
||||
|
||||
it("should not include auto type reference directives", () => {
|
||||
const { host, session, file1 } = setup();
|
||||
const { host, session, file1, file2 } = setup();
|
||||
const atTypes: File = {
|
||||
path: `/node_modules/@types/somemodule/index.d.ts`,
|
||||
content: "export const something = 10;"
|
||||
@@ -107,7 +166,52 @@ class c { prop = "hello"; foo() { return this.prop; } }`
|
||||
openFilesForSession([file1], session);
|
||||
checkNumberOfProjects(service, { inferredProjects: 1 });
|
||||
const project = service.inferredProjects[0];
|
||||
checkProjectActualFiles(project, [libFile.path, file1.path]); // Should not contain atTypes
|
||||
checkProjectActualFiles(project, [libFile.path, file1.path, file2.path]); // Should not contain atTypes
|
||||
});
|
||||
|
||||
it("should not include referenced files from unopened files", () => {
|
||||
const file1: File = {
|
||||
path: `${tscWatch.projectRoot}/a.ts`,
|
||||
content: `///<reference path="b.ts"/>
|
||||
///<reference path="${tscWatch.projectRoot}/node_modules/something/index.d.ts"/>
|
||||
function fooA() { }`
|
||||
};
|
||||
const file2: File = {
|
||||
path: `${tscWatch.projectRoot}/b.ts`,
|
||||
content: `///<reference path="./c.ts"/>
|
||||
///<reference path="${tscWatch.projectRoot}/node_modules/something/index.d.ts"/>
|
||||
function fooB() { }`
|
||||
};
|
||||
const file3: File = {
|
||||
path: `${tscWatch.projectRoot}/c.ts`,
|
||||
content: `function fooC() { }`
|
||||
};
|
||||
const something: File = {
|
||||
path: `${tscWatch.projectRoot}/node_modules/something/index.d.ts`,
|
||||
content: "function something() {}"
|
||||
};
|
||||
const configFile: File = {
|
||||
path: `${tscWatch.projectRoot}/tsconfig.json`,
|
||||
content: "{}"
|
||||
};
|
||||
const host = createServerHost([file1, file2, file3, something, libFile, configFile]);
|
||||
const session = createSession(host, { syntaxOnly: true, useSingleInferredProject: true });
|
||||
const service = session.getProjectService();
|
||||
openFilesForSession([file1], session);
|
||||
checkNumberOfProjects(service, { inferredProjects: 1 });
|
||||
const project = service.inferredProjects[0];
|
||||
checkProjectActualFiles(project, [libFile.path, file1.path, file2.path, something.path]); // Should not contains c
|
||||
|
||||
openFilesForSession([file2], session);
|
||||
checkNumberOfProjects(service, { inferredProjects: 1 });
|
||||
assert.isTrue(project.dirty);
|
||||
project.updateGraph();
|
||||
checkProjectActualFiles(project, [libFile.path, file1.path, file2.path, file3.path, something.path]);
|
||||
|
||||
closeFilesForSession([file2], session);
|
||||
checkNumberOfProjects(service, { inferredProjects: 1 });
|
||||
assert.isFalse(project.dirty);
|
||||
checkProjectActualFiles(project, [libFile.path, file1.path, file2.path, file3.path, something.path]);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user