mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-05 08:11:30 -06:00
Fixes to ensure getDefinitionAndBoundSpan works correctly when using composite projects
Project references need to be detached from the project when closing project In SourceMapDecoder handle when the redirected file to project reference is set as the output of the project Keep configured project alive if project it references has open ref Fixes #26164
This commit is contained in:
parent
9df88316a2
commit
46d223dc1b
@ -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