mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-05 08:11:30 -06:00
Merge pull request #26173 from Microsoft/compositeProjectGoToDefinition
Fixes to ensure getDefinitionAndBoundSpan works correctly when using composite projects
This commit is contained in:
commit
b1878e62bf
@ -2358,7 +2358,7 @@ namespace ts {
|
||||
if (sourceFile === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
sourceFile.path = toPath(refPath);
|
||||
const commandLine = parseJsonSourceFileConfigFileContent(sourceFile, configParsingHost, basePath, /*existingOptions*/ undefined, refPath);
|
||||
return { commandLine, sourceFile };
|
||||
}
|
||||
|
||||
@ -100,7 +100,8 @@ namespace ts.sourcemaps {
|
||||
// Lookup file in program, if provided
|
||||
const path = toPath(fileName, location, host.getCanonicalFileName);
|
||||
const file = program && program.getSourceFile(path);
|
||||
if (!file) {
|
||||
// file returned here could be .d.ts when asked for .ts file if projectReferences and module resolution created this source file
|
||||
if (!file || file.resolvedPath !== path) {
|
||||
// Otherwise check the cache (which may hit disk)
|
||||
return fallbackCache.get(path);
|
||||
}
|
||||
@ -373,4 +374,4 @@ namespace ts.sourcemaps {
|
||||
encodedText.charCodeAt(pos) === CharacterCodes.comma ||
|
||||
encodedText.charCodeAt(pos) === CharacterCodes.semicolon);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2243,6 +2243,20 @@ namespace ts.server {
|
||||
toRemoveConfiguredProjects.delete(project.canonicalConfigFilePath);
|
||||
markOriginalProjectsAsUsed(project);
|
||||
}
|
||||
else {
|
||||
// If the configured project for project reference has more than zero references, keep it alive
|
||||
const resolvedProjectReferences = project.getResolvedProjectReferences();
|
||||
if (resolvedProjectReferences) {
|
||||
for (const ref of resolvedProjectReferences) {
|
||||
if (ref) {
|
||||
const refProject = this.configuredProjects.get(ref.sourceFile.path);
|
||||
if (refProject && refProject.hasOpenRef()) {
|
||||
toRemoveConfiguredProjects.delete(project.canonicalConfigFilePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Remove all the non marked projects
|
||||
|
||||
@ -572,6 +572,14 @@ namespace ts.server {
|
||||
for (const f of this.program.getSourceFiles()) {
|
||||
this.detachScriptInfoIfNotRoot(f.fileName);
|
||||
}
|
||||
const projectReferences = this.program.getProjectReferences();
|
||||
if (projectReferences) {
|
||||
for (const ref of projectReferences) {
|
||||
if (ref) {
|
||||
this.detachScriptInfoFromProject(ref.sourceFile.fileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Release external files
|
||||
forEach(this.externalFiles, externalFile => this.detachScriptInfoIfNotRoot(externalFile));
|
||||
@ -1367,6 +1375,12 @@ namespace ts.server {
|
||||
this.projectReferences = refs;
|
||||
}
|
||||
|
||||
/*@internal*/
|
||||
getResolvedProjectReferences() {
|
||||
const program = this.getCurrentProgram();
|
||||
return program && program.getProjectReferences();
|
||||
}
|
||||
|
||||
enablePlugins() {
|
||||
const host = this.projectService.host;
|
||||
const options = this.getCompilationSettings();
|
||||
|
||||
@ -9183,8 +9183,21 @@ export function Test2() {
|
||||
content: 'import { fnA, instanceA } from "../a/bin/a";\nimport { fnB } from "../b/bin/b";\nexport function fnUser() { fnA(); fnB(); instanceA; }',
|
||||
};
|
||||
|
||||
function makeSampleProjects() {
|
||||
const host = createServerHost([aTs, aTsconfig, aDtsMap, aDts, bTsconfig, bTs, bDtsMap, bDts, userTs, dummyFile]);
|
||||
const userTsForConfigProject: File = {
|
||||
path: "/user/user.ts",
|
||||
content: 'import { fnA, instanceA } from "../a/a";\nimport { fnB } from "../b/b";\nexport function fnUser() { fnA(); fnB(); instanceA; }',
|
||||
};
|
||||
|
||||
const userTsconfig: File = {
|
||||
path: "/user/tsconfig.json",
|
||||
content: JSON.stringify({
|
||||
file: ["user.ts"],
|
||||
references: [{ path: "../a" }, { path: "../b" }]
|
||||
})
|
||||
};
|
||||
|
||||
function makeSampleProjects(addUserTsConfig?: boolean) {
|
||||
const host = createServerHost([aTs, aTsconfig, aDtsMap, aDts, bTsconfig, bTs, bDtsMap, bDts, ...(addUserTsConfig ? [userTsForConfigProject, userTsconfig] : [userTs]), dummyFile]);
|
||||
const session = createSession(host);
|
||||
|
||||
checkDeclarationFiles(aTs, session, [aDtsMap, aDts]);
|
||||
@ -9195,7 +9208,7 @@ export function Test2() {
|
||||
|
||||
openFilesForSession([userTs], session);
|
||||
const service = session.getProjectService();
|
||||
checkNumberOfProjects(service, { inferredProjects: 1 });
|
||||
checkNumberOfProjects(service, addUserTsConfig ? { configuredProjects: 1 } : { inferredProjects: 1 });
|
||||
return session;
|
||||
}
|
||||
|
||||
@ -9247,6 +9260,10 @@ export function Test2() {
|
||||
verifyATsConfigProject(session); // ATsConfig should still be alive
|
||||
}
|
||||
|
||||
function verifyUserTsConfigProject(session: TestSession) {
|
||||
checkProjectActualFiles(session.getProjectService().configuredProjects.get(userTsconfig.path)!, [userTs.path, aDts.path, userTsconfig.path]);
|
||||
}
|
||||
|
||||
it("goToDefinition", () => {
|
||||
const session = makeSampleProjects();
|
||||
const response = executeSessionRequest<protocol.DefinitionRequest, protocol.DefinitionResponse>(session, protocol.CommandTypes.Definition, protocolFileLocationFromSubstring(userTs, "fnA()"));
|
||||
@ -9264,6 +9281,29 @@ export function Test2() {
|
||||
verifySingleInferredProject(session);
|
||||
});
|
||||
|
||||
it("getDefinitionAndBoundSpan with file navigation", () => {
|
||||
const session = makeSampleProjects(/*addUserTsConfig*/ true);
|
||||
const response = executeSessionRequest<protocol.DefinitionAndBoundSpanRequest, protocol.DefinitionAndBoundSpanResponse>(session, protocol.CommandTypes.DefinitionAndBoundSpan, protocolFileLocationFromSubstring(userTs, "fnA()"));
|
||||
assert.deepEqual(response, {
|
||||
textSpan: protocolTextSpanFromSubstring(userTs.content, "fnA", { index: 1 }),
|
||||
definitions: [protocolFileSpanFromSubstring(aTs, "fnA")],
|
||||
});
|
||||
checkNumberOfProjects(session.getProjectService(), { configuredProjects: 1 }); debugger;
|
||||
verifyUserTsConfigProject(session);
|
||||
|
||||
// Navigate to the definition
|
||||
closeFilesForSession([userTs], session);
|
||||
openFilesForSession([aTs], session);
|
||||
|
||||
// UserTs configured project should be alive
|
||||
checkNumberOfProjects(session.getProjectService(), { configuredProjects: 2 });
|
||||
verifyUserTsConfigProject(session);
|
||||
verifyATsConfigProject(session);
|
||||
|
||||
closeFilesForSession([aTs], session);
|
||||
verifyOnlyOrphanInferredProject(session);
|
||||
});
|
||||
|
||||
it("goToType", () => {
|
||||
const session = makeSampleProjects();
|
||||
const response = executeSessionRequest<protocol.TypeDefinitionRequest, protocol.TypeDefinitionResponse>(session, protocol.CommandTypes.TypeDefinition, protocolFileLocationFromSubstring(userTs, "instanceA"));
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user