Skip to content

Commit 47946ff

Browse files
committed
Try to find project from project references if the default config project is solution
Fixes #36708
1 parent 0716898 commit 47946ff

File tree

2 files changed

+48
-23
lines changed

2 files changed

+48
-23
lines changed

src/server/editorServices.ts

Lines changed: 45 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -308,7 +308,7 @@ namespace ts.server {
308308
}
309309

310310
interface AssignProjectResult extends OpenConfiguredProjectResult {
311-
defaultConfigProject: ConfiguredProject | undefined;
311+
retainProjects: readonly ConfiguredProject[] | ConfiguredProject | undefined;
312312
}
313313

314314
interface FilePropertyReader<T> {
@@ -2860,6 +2860,7 @@ namespace ts.server {
28602860
let configFileErrors: readonly Diagnostic[] | undefined;
28612861
let project: ConfiguredProject | ExternalProject | undefined = this.findExternalProjectContainingOpenScriptInfo(info);
28622862
let defaultConfigProject: ConfiguredProject | undefined;
2863+
let retainProjects: ConfiguredProject[] | ConfiguredProject | undefined;
28632864
if (!project && !this.syntaxOnly) { // Checking syntaxOnly is an optimization
28642865
configFileName = this.getConfigFileNameForFile(info);
28652866
if (configFileName) {
@@ -2880,7 +2881,42 @@ namespace ts.server {
28802881
// Ensure project is ready to check if it contains opened script info
28812882
updateProjectIfDirty(project);
28822883
}
2884+
28832885
defaultConfigProject = project;
2886+
retainProjects = defaultConfigProject;
2887+
2888+
// If this configured project doesnt contain script info but
2889+
// it is solution with project references, try those project references
2890+
if (!project.containsScriptInfo(info) &&
2891+
project.getRootFilesMap().size === 0 &&
2892+
!project.canConfigFileJsonReportNoInputFiles) {
2893+
2894+
// try to load project from the tree
2895+
forEachResolvedProjectReference(
2896+
project,
2897+
ref => {
2898+
if (!ref) return;
2899+
2900+
// Try to load the project of resolvedRef
2901+
const configFileName = toNormalizedPath(ref.sourceFile.fileName);
2902+
const child = this.findConfiguredProjectByProjectName(configFileName) ||
2903+
this.createAndLoadConfiguredProject(configFileName, `Creating project referenced in solution ${defaultConfigProject!.projectName} to find possible configured project for ${info.fileName} to open`);
2904+
// Retain these projects
2905+
if (!isArray(retainProjects)) {
2906+
retainProjects = [defaultConfigProject!, child];
2907+
}
2908+
else {
2909+
retainProjects.push(child);
2910+
}
2911+
2912+
if (child.containsScriptInfo(info)) {
2913+
defaultConfigProject = child;
2914+
return true;
2915+
}
2916+
}
2917+
);
2918+
}
2919+
28842920
// Create ancestor configured project
28852921
this.createAncestorProjects(info, defaultConfigProject);
28862922
}
@@ -2902,7 +2938,7 @@ namespace ts.server {
29022938
this.assignOrphanScriptInfoToInferredProject(info, this.openFiles.get(info.path));
29032939
}
29042940
Debug.assert(!info.isOrphan());
2905-
return { configFileName, configFileErrors, defaultConfigProject };
2941+
return { configFileName, configFileErrors, retainProjects };
29062942
}
29072943

29082944
private createAncestorProjects(info: ScriptInfo, project: ConfiguredProject) {
@@ -2978,7 +3014,7 @@ namespace ts.server {
29783014
);
29793015
}
29803016

2981-
private cleanupAfterOpeningFile(toRetainConfigProjects: ConfiguredProject[] | ConfiguredProject | undefined) {
3017+
private cleanupAfterOpeningFile(toRetainConfigProjects: readonly ConfiguredProject[] | ConfiguredProject | undefined) {
29823018
// This was postponed from closeOpenFile to after opening next file,
29833019
// so that we can reuse the project if we need to right away
29843020
this.removeOrphanConfiguredProjects(toRetainConfigProjects);
@@ -3000,14 +3036,14 @@ namespace ts.server {
30003036

30013037
openClientFileWithNormalizedPath(fileName: NormalizedPath, fileContent?: string, scriptKind?: ScriptKind, hasMixedContent?: boolean, projectRootPath?: NormalizedPath): OpenConfiguredProjectResult {
30023038
const info = this.getOrCreateOpenScriptInfo(fileName, fileContent, scriptKind, hasMixedContent, projectRootPath);
3003-
const { defaultConfigProject, ...result } = this.assignProjectToOpenedScriptInfo(info);
3004-
this.cleanupAfterOpeningFile(defaultConfigProject);
3039+
const { retainProjects, ...result } = this.assignProjectToOpenedScriptInfo(info);
3040+
this.cleanupAfterOpeningFile(retainProjects);
30053041
this.telemetryOnOpenFile(info);
30063042
this.printProjects();
30073043
return result;
30083044
}
30093045

3010-
private removeOrphanConfiguredProjects(toRetainConfiguredProjects: ConfiguredProject[] | ConfiguredProject | undefined) {
3046+
private removeOrphanConfiguredProjects(toRetainConfiguredProjects: readonly ConfiguredProject[] | ConfiguredProject | undefined) {
30113047
const toRemoveConfiguredProjects = cloneMap(this.configuredProjects);
30123048
const markOriginalProjectsAsUsed = (project: Project) => {
30133049
if (!project.isOrphan() && project.originalConfiguredProjects) {
@@ -3206,9 +3242,9 @@ namespace ts.server {
32063242
}
32073243

32083244
// All the script infos now exist, so ok to go update projects for open files
3209-
let defaultConfigProjects: ConfiguredProject[] | undefined;
3245+
let retainProjects: readonly ConfiguredProject[] | undefined;
32103246
if (openScriptInfos) {
3211-
defaultConfigProjects = mapDefined(openScriptInfos, info => this.assignProjectToOpenedScriptInfo(info).defaultConfigProject);
3247+
retainProjects = flatMap(openScriptInfos, info => this.assignProjectToOpenedScriptInfo(info).retainProjects);
32123248
}
32133249

32143250
// While closing files there could be open files that needed assigning new inferred projects, do it now
@@ -3218,7 +3254,7 @@ namespace ts.server {
32183254

32193255
if (openScriptInfos) {
32203256
// Cleanup projects
3221-
this.cleanupAfterOpeningFile(defaultConfigProjects);
3257+
this.cleanupAfterOpeningFile(retainProjects);
32223258
// Telemetry
32233259
openScriptInfos.forEach(info => this.telemetryOnOpenFile(info));
32243260
this.printProjects();

src/testRunner/unittests/tsserver/projectReferences.ts

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1872,26 +1872,15 @@ foo;`
18721872
const session = createSession(host, { canUseEvents: true });
18731873
const service = session.getProjectService();
18741874
service.openClientFile(main.path);
1875-
checkNumberOfProjects(service, { configuredProjects: 1, inferredProjects: 1 });
1876-
checkProjectActualFiles(service.inferredProjects[0], [main.path, libFile.path]);
1875+
checkNumberOfProjects(service, { configuredProjects: 2 });
1876+
checkProjectActualFiles(service.configuredProjects.get(tsconfigSrc.path)!, [tsconfigSrc.path, main.path, helper.path, libFile.path]);
18771877
checkProjectActualFiles(service.configuredProjects.get(tsconfig.path)!, [tsconfig.path]);
18781878

1879-
const location = protocolTextSpanFromSubstring(main.content, `'helpers/functions'`);
18801879
verifyGetErrRequest({
18811880
session,
18821881
host,
18831882
expected: [
1884-
{
1885-
file: main,
1886-
syntax: [],
1887-
semantic: [createDiagnostic(
1888-
location.start,
1889-
location.end,
1890-
Diagnostics.Cannot_find_module_0,
1891-
["helpers/functions"]
1892-
)],
1893-
suggestion: []
1894-
},
1883+
{ file: main, syntax: [], semantic: [], suggestion: [] },
18951884
]
18961885
});
18971886
});

0 commit comments

Comments
 (0)