Skip to content

Commit a825d67

Browse files
committed
Load the ancestor projects to find default project for the file
1 parent ab24e12 commit a825d67

File tree

156 files changed

+3860
-2530
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

156 files changed

+3860
-2530
lines changed

src/harness/projectServiceStateLogger.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,11 @@ export function patchServiceForStateBaseline(service: ProjectService) {
104104
function baselineProjects(currentMappers: Set<DocumentPositionMapper>) {
105105
const autoImportProviderProjects = [] as AutoImportProviderProject[];
106106
const auxiliaryProjects = [] as AuxiliaryProject[];
107-
const orphanConfiguredProjects = service.getOrphanConfiguredProjects(/*toRetainConfiguredProjects*/ undefined);
107+
const orphanConfiguredProjects = service.getOrphanConfiguredProjects(
108+
/*toRetainConfiguredProjects*/ undefined,
109+
/*openFilesWithRetainedConfiguredProject*/ undefined,
110+
/*externalProjectsRetainingConfiguredProjects*/ undefined,
111+
);
108112
const noOpenRef = (project: Project) => isConfiguredProject(project) && (project.isClosed() || orphanConfiguredProjects.has(project));
109113
return baselineState(
110114
[service.externalProjects, service.configuredProjects, service.inferredProjects, autoImportProviderProjects, auxiliaryProjects],

src/server/editorServices.ts

Lines changed: 544 additions & 328 deletions
Large diffs are not rendered by default.

src/server/project.ts

Lines changed: 2 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -141,15 +141,12 @@ import {
141141
emptyArray,
142142
Errors,
143143
FileStats,
144-
forEachResolvedProjectReferenceProject,
145144
LogLevel,
146145
ModuleImportResult,
147146
Msg,
148147
NormalizedPath,
149148
PackageJsonWatcher,
150-
projectContainsInfoDirectly,
151149
ProjectOptions,
152-
ProjectReferenceProjectLoadKind,
153150
ProjectService,
154151
ScriptInfo,
155152
ServerHost,
@@ -2211,7 +2208,7 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo
22112208
private isDefaultProjectForOpenFiles(): boolean {
22122209
return !!forEachEntry(
22132210
this.projectService.openFiles,
2214-
(_, fileName) => this.projectService.tryGetDefaultProjectForFile(toNormalizedPath(fileName)) === this,
2211+
(_projectRootPath, path) => this.projectService.tryGetDefaultProjectForFile(this.projectService.getScriptInfoForPath(path)!) === this,
22152212
);
22162213
}
22172214

@@ -2751,9 +2748,6 @@ export class ConfiguredProject extends Project {
27512748
/** @internal */
27522749
canConfigFileJsonReportNoInputFiles = false;
27532750

2754-
/** Ref count to the project when opened from external project */
2755-
private externalProjectRefCount = 0;
2756-
27572751
private projectReferences: readonly ProjectReference[] | undefined;
27582752

27592753
/**
@@ -2858,8 +2852,7 @@ export class ConfiguredProject extends Project {
28582852
case ProgramUpdateLevel.Full:
28592853
this.openFileWatchTriggered.clear();
28602854
const reason = Debug.checkDefined(this.pendingUpdateReason);
2861-
this.pendingUpdateReason = undefined;
2862-
this.projectService.reloadConfiguredProject(this, reason, isInitialLoad, /*clearSemanticCache*/ false);
2855+
this.projectService.reloadConfiguredProject(this, reason, isInitialLoad);
28632856
result = true;
28642857
break;
28652858
default:
@@ -2970,91 +2963,17 @@ export class ConfiguredProject extends Project {
29702963
super.markAsDirty();
29712964
}
29722965

2973-
/** @internal */
2974-
addExternalProjectReference() {
2975-
this.externalProjectRefCount++;
2976-
}
2977-
2978-
/** @internal */
2979-
deleteExternalProjectReference() {
2980-
this.externalProjectRefCount--;
2981-
}
2982-
29832966
/** @internal */
29842967
isSolution() {
29852968
return this.getRootFilesMap().size === 0 &&
29862969
!this.canConfigFileJsonReportNoInputFiles;
29872970
}
29882971

2989-
/**
2990-
* Find the configured project from the project references in project which contains the info directly
2991-
*
2992-
* @internal
2993-
*/
2994-
getDefaultChildProjectFromProjectWithReferences(info: ScriptInfo) {
2995-
return forEachResolvedProjectReferenceProject(
2996-
this,
2997-
info.path,
2998-
child =>
2999-
projectContainsInfoDirectly(child, info) ?
3000-
child :
3001-
undefined,
3002-
ProjectReferenceProjectLoadKind.Find,
3003-
);
3004-
}
3005-
3006-
/**
3007-
* Returns true if the project is needed by any of the open script info/external project
3008-
*
3009-
* @internal
3010-
*/
3011-
hasOpenRef() {
3012-
if (!!this.externalProjectRefCount) {
3013-
return true;
3014-
}
3015-
3016-
// Closed project doesnt have any reference
3017-
if (this.isClosed()) {
3018-
return false;
3019-
}
3020-
3021-
const configFileExistenceInfo = this.projectService.configFileExistenceInfoCache.get(this.canonicalConfigFilePath)!;
3022-
if (this.deferredClose) return !!configFileExistenceInfo.openFilesImpactedByConfigFile?.size;
3023-
if (this.projectService.hasPendingProjectUpdate(this)) {
3024-
// If there is pending update for this project,
3025-
// we dont know if this project would be needed by any of the open files impacted by this config file
3026-
// In that case keep the project alive if there are open files impacted by this project
3027-
return !!configFileExistenceInfo.openFilesImpactedByConfigFile?.size;
3028-
}
3029-
3030-
// If there is no pending update for this project,
3031-
// We know exact set of open files that get impacted by this configured project as the files in the project
3032-
// The project is referenced only if open files impacted by this project are present in this project
3033-
return !!configFileExistenceInfo.openFilesImpactedByConfigFile && forEachEntry(
3034-
configFileExistenceInfo.openFilesImpactedByConfigFile,
3035-
(_value, infoPath) => {
3036-
const info = this.projectService.getScriptInfoForPath(infoPath)!;
3037-
return this.containsScriptInfo(info) ||
3038-
!!forEachResolvedProjectReferenceProject(
3039-
this,
3040-
info.path,
3041-
child => child.containsScriptInfo(info),
3042-
ProjectReferenceProjectLoadKind.Find,
3043-
);
3044-
},
3045-
) || false;
3046-
}
3047-
30482972
/** @internal */
30492973
override isOrphan(): boolean {
30502974
return !!this.deferredClose;
30512975
}
30522976

3053-
/** @internal */
3054-
hasExternalProjectRef() {
3055-
return !!this.externalProjectRefCount;
3056-
}
3057-
30582977
getEffectiveTypeRoots() {
30592978
return getEffectiveTypeRoots(this.getCompilationSettings(), this) || [];
30602979
}

src/server/scriptInfo.ts

Lines changed: 10 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ import {
3939
AbsolutePositionAndLineText,
4040
ConfiguredProject,
4141
Errors,
42-
ExternalProject,
4342
InferredProject,
4443
isBackgroundProject,
4544
isConfiguredProject,
@@ -580,18 +579,16 @@ export class ScriptInfo {
580579
case 0:
581580
return Errors.ThrowNoProject();
582581
case 1:
583-
return ensurePrimaryProjectKind(
584-
!isProjectDeferredClose(this.containingProjects[0]) ?
585-
this.containingProjects[0] : undefined,
586-
);
582+
return isProjectDeferredClose(this.containingProjects[0]) || isBackgroundProject(this.containingProjects[0]) ?
583+
Errors.ThrowNoProject() :
584+
this.containingProjects[0];
587585
default:
588586
// If this file belongs to multiple projects, below is the order in which default project is used
587+
// - first external project
589588
// - for open script info, its default configured project during opening is default if info is part of it
590589
// - first configured project of which script info is not a source of project reference redirect
591590
// - first configured project
592-
// - first external project
593591
// - first inferred project
594-
let firstExternalProject: ExternalProject | undefined;
595592
let firstConfiguredProject: ConfiguredProject | undefined;
596593
let firstInferredProject: InferredProject | undefined;
597594
let firstNonSourceOfProjectReferenceRedirect: ConfiguredProject | undefined;
@@ -614,20 +611,17 @@ export class ScriptInfo {
614611
}
615612
if (!firstConfiguredProject) firstConfiguredProject = project;
616613
}
617-
else if (!firstExternalProject && isExternalProject(project)) {
618-
firstExternalProject = project;
614+
else if (isExternalProject(project)) {
615+
return project;
619616
}
620617
else if (!firstInferredProject && isInferredProject(project)) {
621618
firstInferredProject = project;
622619
}
623620
}
624-
return ensurePrimaryProjectKind(
625-
defaultConfiguredProject ||
626-
firstNonSourceOfProjectReferenceRedirect ||
627-
firstConfiguredProject ||
628-
firstExternalProject ||
629-
firstInferredProject,
630-
);
621+
return (defaultConfiguredProject ||
622+
firstNonSourceOfProjectReferenceRedirect ||
623+
firstConfiguredProject ||
624+
firstInferredProject) ?? Errors.ThrowNoProject();
631625
}
632626
}
633627

@@ -742,18 +736,6 @@ export class ScriptInfo {
742736
}
743737
}
744738

745-
/**
746-
* Throws an error if `project` is an AutoImportProvider or AuxiliaryProject,
747-
* which are used in the background by other Projects and should never be
748-
* reported as the default project for a ScriptInfo.
749-
*/
750-
function ensurePrimaryProjectKind(project: Project | undefined) {
751-
if (!project || isBackgroundProject(project)) {
752-
return Errors.ThrowNoProject();
753-
}
754-
return project;
755-
}
756-
757739
function failIfInvalidPosition(position: number) {
758740
Debug.assert(typeof position === "number", `Expected position ${position} to be a number.`);
759741
Debug.assert(position >= 0, `Expected position to be non-negative.`);

src/server/session.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3190,7 +3190,7 @@ export class Session<TMessage = string> implements EventSender {
31903190
return this.requiredResponse(response);
31913191
},
31923192
[protocol.CommandTypes.OpenExternalProject]: (request: protocol.OpenExternalProjectRequest) => {
3193-
this.projectService.openExternalProject(request.arguments, /*print*/ true);
3193+
this.projectService.openExternalProject(request.arguments, /*cleanupAfter*/ true);
31943194
// TODO: GH#20447 report errors
31953195
return this.requiredResponse(/*response*/ true);
31963196
},
@@ -3200,7 +3200,7 @@ export class Session<TMessage = string> implements EventSender {
32003200
return this.requiredResponse(/*response*/ true);
32013201
},
32023202
[protocol.CommandTypes.CloseExternalProject]: (request: protocol.CloseExternalProjectRequest) => {
3203-
this.projectService.closeExternalProject(request.arguments.projectFileName, /*print*/ true);
3203+
this.projectService.closeExternalProject(request.arguments.projectFileName, /*cleanupAfter*/ true);
32043204
// TODO: GH#20447 report errors
32053205
return this.requiredResponse(/*response*/ true);
32063206
},

src/testRunner/unittests/tsserver/projects.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ describe("unittests:: tsserver:: projects::", () => {
177177
};
178178
session.host.baselineHost("Before request");
179179
session.logger.info(`request:${ts.server.stringifyIndented(request)}`);
180-
session.getProjectService().openExternalProject(request.arguments, /*print*/ true);
180+
session.getProjectService().openExternalProject(request.arguments, /*cleanupAfter*/ true);
181181
session.host.baselineHost("After request");
182182
baselineTsserverLogs("projects", "external project including config file", session);
183183
});

tests/baselines/reference/api/typescript.d.ts

Lines changed: 8 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2872,8 +2872,6 @@ declare namespace ts {
28722872
*/
28732873
class ConfiguredProject extends Project {
28742874
readonly canonicalConfigFilePath: NormalizedPath;
2875-
/** Ref count to the project when opened from external project */
2876-
private externalProjectRefCount;
28772875
private projectReferences;
28782876
/**
28792877
* If the project has reload from disk pending, it reloads (and then updates graph as part of that) instead of just updating the graph
@@ -3135,6 +3133,7 @@ declare namespace ts {
31353133
private safelist;
31363134
private readonly legacySafelist;
31373135
private pendingProjectUpdates;
3136+
private pendingOpenFileProjectUpdates?;
31383137
readonly currentDirectory: NormalizedPath;
31393138
readonly toCanonicalFileName: (f: string) => string;
31403139
readonly host: ServerHost;
@@ -3185,13 +3184,6 @@ declare namespace ts {
31853184
private delayUpdateSourceInfoProjects;
31863185
private delayUpdateProjectsOfScriptInfoPath;
31873186
private handleDeletedFile;
3188-
/**
3189-
* This function goes through all the openFiles and tries to file the config file for them.
3190-
* If the config file is found and it refers to existing project, it schedules the reload it for reload
3191-
* If there is no existing project it just opens the configured project for the config file
3192-
* shouldReloadProjectFor provides a way to filter out files to reload configured project for
3193-
*/
3194-
private delayReloadConfiguredProjectsForFile;
31953187
private removeProject;
31963188
private assignOrphanScriptInfosToInferredProject;
31973189
/**
@@ -3218,6 +3210,8 @@ declare namespace ts {
32183210
* the newly opened file.
32193211
*/
32203212
private forEachConfigFileLocation;
3213+
private getConfigFileNameForFileFromCache;
3214+
private setConfigFileNameForFileInCache;
32213215
/**
32223216
* This function tries to search for a tsconfig.json for the given file.
32233217
* This is different from the method the compiler uses because
@@ -3269,12 +3263,6 @@ declare namespace ts {
32693263
* This does not reload contents of open files from disk. But we could do that if needed
32703264
*/
32713265
reloadProjects(): void;
3272-
/**
3273-
* This function goes through all the openFiles and tries to file the config file for them.
3274-
* If the config file is found and it refers to existing project, it reloads it either immediately
3275-
* If there is no existing project it just opens the configured project for the config file
3276-
*/
3277-
private reloadConfiguredProjectForFiles;
32783266
/**
32793267
* Remove the root of inferred project if script info is part of another project
32803268
*/
@@ -3295,12 +3283,14 @@ declare namespace ts {
32953283
openClientFile(fileName: string, fileContent?: string, scriptKind?: ScriptKind, projectRootPath?: string): OpenConfiguredProjectResult;
32963284
private findExternalProjectContainingOpenScriptInfo;
32973285
private getOrCreateOpenScriptInfo;
3286+
private tryFindDefaultConfiguredProjectForOpenScriptInfo;
3287+
private tryFindDefaultConfiguredProjectAndLoadAncestorsForOpenScriptInfo;
32983288
private assignProjectToOpenedScriptInfo;
3299-
private createAncestorProjects;
3289+
private forEachAncestorProject;
33003290
private ensureProjectChildren;
3301-
private cleanupAfterOpeningFile;
3291+
private cleanupConfiguredProjects;
3292+
private cleanupProjectsAndScriptInfos;
33023293
openClientFileWithNormalizedPath(fileName: NormalizedPath, fileContent?: string, scriptKind?: ScriptKind, hasMixedContent?: boolean, projectRootPath?: NormalizedPath): OpenConfiguredProjectResult;
3303-
private removeOrphanConfiguredProjects;
33043294
private removeOrphanScriptInfos;
33053295
private telemetryOnOpenFile;
33063296
/**
@@ -3309,7 +3299,6 @@ declare namespace ts {
33093299
*/
33103300
closeClientFile(uncheckedFileName: string): void;
33113301
private collectChanges;
3312-
private closeConfiguredProjectReferencedFromExternalProject;
33133302
closeExternalProject(uncheckedFileName: string): void;
33143303
openExternalProjects(projects: protocol.ExternalProject[]): void;
33153304
/** Makes a filename safe to insert in a RegExp */

tests/baselines/reference/tsserver/configFileSearch/tsconfig-for-the-file-does-not-exist.js

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -110,12 +110,11 @@ Info seq [hh:mm:ss:mss] Scheduled: *ensureProjectForOpenFiles*
110110
Info seq [hh:mm:ss:mss] Elapsed:: *ms FileWatcher:: Triggered with /a/b/projects/project/tsconfig.json 0:: WatchInfo: /a/b/projects/project/tsconfig.json 2000 undefined WatchType: Config file for the inferred project root
111111
Info seq [hh:mm:ss:mss] FileWatcher:: Triggered with /a/b/projects/project/tsconfig.json 0:: WatchInfo: /a/b/projects/project/tsconfig.json 2000 undefined WatchType: Config file for the inferred project root
112112
Info seq [hh:mm:ss:mss] getConfigFileNameForFile:: File: /a/b/projects/project/src/index.ts ProjectRootPath: /a/b/projects/proj:: Result: /a/b/projects/project/tsconfig.json
113-
Info seq [hh:mm:ss:mss] Scheduled: /a/b/projects/project/tsconfig.json, Cancelled earlier one
114113
Info seq [hh:mm:ss:mss] Scheduled: *ensureProjectForOpenFiles*, Cancelled earlier one
115114
Info seq [hh:mm:ss:mss] Elapsed:: *ms FileWatcher:: Triggered with /a/b/projects/project/tsconfig.json 0:: WatchInfo: /a/b/projects/project/tsconfig.json 2000 undefined WatchType: Config file for the inferred project root
116115
Before running Timeout callback:: count: 2
117-
3: /a/b/projects/project/tsconfig.json
118-
4: *ensureProjectForOpenFiles*
116+
1: /a/b/projects/project/tsconfig.json
117+
3: *ensureProjectForOpenFiles*
119118
//// [/a/b/projects/project/tsconfig.json]
120119
{}
121120

@@ -145,8 +144,8 @@ FsWatches::
145144
{}
146145

147146
Timeout callback:: count: 2
148-
3: /a/b/projects/project/tsconfig.json *new*
149-
4: *ensureProjectForOpenFiles* *new*
147+
1: /a/b/projects/project/tsconfig.json *new*
148+
3: *ensureProjectForOpenFiles* *new*
150149

151150
Projects::
152151
/a/b/projects/project/tsconfig.json (Configured) *new*
@@ -364,11 +363,11 @@ Info seq [hh:mm:ss:mss] DirectoryWatcher:: Triggered with /a/b/projects/project
364363
Info seq [hh:mm:ss:mss] Project: /a/b/projects/project/tsconfig.json Detected file add/remove of non supported extension: /a/b/projects/project/tsconfig.json
365364
Info seq [hh:mm:ss:mss] Elapsed:: *ms DirectoryWatcher:: Triggered with /a/b/projects/project/tsconfig.json :: WatchInfo: /a/b/projects/project 1 undefined Config: /a/b/projects/project/tsconfig.json WatchType: Wild card directory
366365
Before running Timeout callback:: count: 1
367-
5: *ensureProjectForOpenFiles*
366+
4: *ensureProjectForOpenFiles*
368367
//// [/a/b/projects/project/tsconfig.json] deleted
369368

370369
Timeout callback:: count: 1
371-
5: *ensureProjectForOpenFiles* *new*
370+
4: *ensureProjectForOpenFiles* *new*
372371

373372
Projects::
374373
/a/b/projects/project/tsconfig.json (Configured) *changed*

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy