Send even for ProjectLoadStart and ProjectLoadFinish

Fixes #27206
This commit is contained in:
Sheetal Nandi
2018-10-05 15:09:33 -07:00
parent c080324974
commit 37e25c8873
6 changed files with 336 additions and 73 deletions
+71 -18
View File
@@ -5,6 +5,8 @@ namespace ts.server {
// tslint:disable variable-name
export const ProjectsUpdatedInBackgroundEvent = "projectsUpdatedInBackground";
export const ProjectLoadingStartEvent = "projectLoadingStart";
export const ProjectLoadingFinishEvent = "projectLoadingFinish";
export const SurveyReady = "surveyReady";
export const LargeFileReferencedEvent = "largeFileReferenced";
export const ConfigFileDiagEvent = "configFileDiag";
@@ -18,6 +20,16 @@ namespace ts.server {
data: { openFiles: string[]; };
}
export interface ProjectLoadingStartEvent {
eventName: typeof ProjectLoadingStartEvent;
data: { project: Project; reason: string; };
}
export interface ProjectLoadingFinishEvent {
eventName: typeof ProjectLoadingFinishEvent;
data: { project: Project; };
}
export interface SurveyReady {
eventName: typeof SurveyReady;
data: { surveyId: string; };
@@ -122,7 +134,15 @@ namespace ts.server {
readonly checkJs: boolean;
}
export type ProjectServiceEvent = LargeFileReferencedEvent | SurveyReady | ProjectsUpdatedInBackgroundEvent | ConfigFileDiagEvent | ProjectLanguageServiceStateEvent | ProjectInfoTelemetryEvent | OpenFileInfoTelemetryEvent;
export type ProjectServiceEvent = LargeFileReferencedEvent |
SurveyReady |
ProjectsUpdatedInBackgroundEvent |
ProjectLoadingStartEvent |
ProjectLoadingFinishEvent |
ConfigFileDiagEvent |
ProjectLanguageServiceStateEvent |
ProjectInfoTelemetryEvent |
OpenFileInfoTelemetryEvent;
export type ProjectServiceEventHandler = (event: ProjectServiceEvent) => void;
@@ -721,6 +741,33 @@ namespace ts.server {
this.eventHandler(event);
}
/* @internal */
sendProjectLoadingStartEvent(project: ConfiguredProject, reason: string) {
if (!this.eventHandler) {
return;
}
project.sendLoadingProjectFinish = true;
const event: ProjectLoadingStartEvent = {
eventName: ProjectLoadingStartEvent,
data: { project, reason }
};
this.eventHandler(event);
}
/* @internal */
sendProjectLoadingFinishEvent(project: ConfiguredProject) {
if (!this.eventHandler || !project.sendLoadingProjectFinish) {
return;
}
project.sendLoadingProjectFinish = false;
const event: ProjectLoadingFinishEvent = {
eventName: ProjectLoadingFinishEvent,
data: { project }
};
this.eventHandler(event);
}
/* @internal */
delayUpdateProjectGraphAndEnsureProjectStructureForOpenFiles(project: Project) {
this.delayUpdateProjectGraph(project);
@@ -955,6 +1002,7 @@ namespace ts.server {
else {
this.logConfigFileWatchUpdate(project.getConfigFilePath(), project.canonicalConfigFilePath, configFileExistenceInfo, ConfigFileWatcherStatus.ReloadingInferredRootFiles);
project.pendingReload = ConfigFileProgramReloadLevel.Full;
project.pendingReloadReason = "Change in config file detected";
this.delayUpdateProjectGraph(project);
// As we scheduled the update on configured project graph,
// we would need to schedule the project reload for only the root of inferred projects
@@ -1613,22 +1661,23 @@ namespace ts.server {
}
/* @internal */
private createConfiguredProjectWithDelayLoad(configFileName: NormalizedPath) {
private createConfiguredProjectWithDelayLoad(configFileName: NormalizedPath, reason: string) {
const project = this.createConfiguredProject(configFileName);
project.pendingReload = ConfigFileProgramReloadLevel.Full;
project.pendingReloadReason = reason;
return project;
}
/* @internal */
private createAndLoadConfiguredProject(configFileName: NormalizedPath) {
private createAndLoadConfiguredProject(configFileName: NormalizedPath, reason: string) {
const project = this.createConfiguredProject(configFileName);
this.loadConfiguredProject(project);
this.loadConfiguredProject(project, reason);
return project;
}
/* @internal */
private createLoadAndUpdateConfiguredProject(configFileName: NormalizedPath) {
const project = this.createAndLoadConfiguredProject(configFileName);
private createLoadAndUpdateConfiguredProject(configFileName: NormalizedPath, reason: string) {
const project = this.createAndLoadConfiguredProject(configFileName, reason);
project.updateGraph();
return project;
}
@@ -1637,7 +1686,9 @@ namespace ts.server {
* Read the config file of the project, and update the project root file names.
*/
/* @internal */
private loadConfiguredProject(project: ConfiguredProject) {
private loadConfiguredProject(project: ConfiguredProject, reason: string) {
this.sendProjectLoadingStartEvent(project, reason);
// Read updated contents from disk
const configFilename = normalizePath(project.getConfigFilePath());
@@ -1776,7 +1827,7 @@ namespace ts.server {
* Read the config file of the project again by clearing the cache and update the project graph
*/
/* @internal */
reloadConfiguredProject(project: ConfiguredProject) {
reloadConfiguredProject(project: ConfiguredProject, reason: string) {
// At this point, there is no reason to not have configFile in the host
const host = project.getCachedDirectoryStructureHost();
@@ -1786,7 +1837,7 @@ namespace ts.server {
this.logger.info(`Reloading configured project ${configFileName}`);
// Load project from the disk
this.loadConfiguredProject(project);
this.loadConfiguredProject(project, reason);
project.updateGraph();
this.sendConfigFileDiagEvent(project, configFileName);
@@ -2139,7 +2190,6 @@ namespace ts.server {
if (project.hasExternalProjectRef() &&
project.pendingReload === ConfigFileProgramReloadLevel.Full &&
!this.pendingProjectUpdates.has(project.getProjectName())) {
this.loadConfiguredProject(project);
project.updateGraph();
}
});
@@ -2171,7 +2221,7 @@ namespace ts.server {
// as there is no need to load contents of the files from the disk
// Reload Projects
this.reloadConfiguredProjectForFiles(this.openFiles, /*delayReload*/ false, returnTrue);
this.reloadConfiguredProjectForFiles(this.openFiles, /*delayReload*/ false, returnTrue, "User requested reload projects");
this.ensureProjectForOpenFiles();
}
@@ -2182,7 +2232,8 @@ namespace ts.server {
/*delayReload*/ true,
ignoreIfNotRootOfInferredProject ?
isRootOfInferredProject => isRootOfInferredProject : // Reload open files if they are root of inferred project
returnTrue // Reload all the open files impacted by config file
returnTrue, // Reload all the open files impacted by config file
"Change in config file detected"
);
this.delayEnsureProjectForOpenFiles();
}
@@ -2194,7 +2245,7 @@ namespace ts.server {
* If the there is no existing project it just opens the configured project for the config file
* reloadForInfo provides a way to filter out files to reload configured project for
*/
private reloadConfiguredProjectForFiles<T>(openFiles: Map<T>, delayReload: boolean, shouldReloadProjectFor: (openFileValue: T) => boolean) {
private reloadConfiguredProjectForFiles<T>(openFiles: Map<T>, delayReload: boolean, shouldReloadProjectFor: (openFileValue: T) => boolean, reason: string) {
const updatedProjects = createMap<true>();
// try to reload config file for all open files
openFiles.forEach((openFileValue, path) => {
@@ -2215,11 +2266,12 @@ namespace ts.server {
if (!updatedProjects.has(configFileName)) {
if (delayReload) {
project.pendingReload = ConfigFileProgramReloadLevel.Full;
project.pendingReloadReason = reason;
this.delayUpdateProjectGraph(project);
}
else {
// reload from the disk
this.reloadConfiguredProject(project);
this.reloadConfiguredProject(project, reason);
}
updatedProjects.set(configFileName, true);
}
@@ -2306,7 +2358,8 @@ namespace ts.server {
const configFileName = this.getConfigFileNameForFile(originalFileInfo);
if (!configFileName) return undefined;
const configuredProject = this.findConfiguredProjectByProjectName(configFileName) || this.createAndLoadConfiguredProject(configFileName);
const configuredProject = this.findConfiguredProjectByProjectName(configFileName) ||
this.createAndLoadConfiguredProject(configFileName, `Creating project for original file: ${originalFileInfo.fileName} for location: ${location.fileName}`);
updateProjectIfDirty(configuredProject);
// Keep this configured project as referenced from project
addOriginalConfiguredProject(configuredProject);
@@ -2356,7 +2409,7 @@ namespace ts.server {
if (configFileName) {
project = this.findConfiguredProjectByProjectName(configFileName);
if (!project) {
project = this.createLoadAndUpdateConfiguredProject(configFileName);
project = this.createLoadAndUpdateConfiguredProject(configFileName, `Creating possible configured project for ${fileName} to open`);
// Send the event only if the project got created as part of this open request and info is part of the project
if (info.isOrphan()) {
// Since the file isnt part of configured project, do not send config file info
@@ -2797,8 +2850,8 @@ namespace ts.server {
if (!project) {
// errors are stored in the project, do not need to update the graph
project = this.getHostPreferences().lazyConfiguredProjectsFromExternalProject ?
this.createConfiguredProjectWithDelayLoad(tsconfigFile) :
this.createLoadAndUpdateConfiguredProject(tsconfigFile);
this.createConfiguredProjectWithDelayLoad(tsconfigFile, `Creating configured project in external project: ${proj.projectFileName}`) :
this.createLoadAndUpdateConfiguredProject(tsconfigFile, `Creating configured project in external project: ${proj.projectFileName}`);
}
if (project && !contains(exisingConfigFiles, tsconfigFile)) {
// keep project alive even if no documents are opened - its lifetime is bound to the lifetime of containing external project
+9 -1
View File
@@ -1320,6 +1320,8 @@ namespace ts.server {
/* @internal */
pendingReload: ConfigFileProgramReloadLevel;
/* @internal */
pendingReloadReason: string | undefined;
/*@internal*/
configFileSpecs: ConfigFileSpecs | undefined;
@@ -1339,6 +1341,9 @@ namespace ts.server {
protected isInitialLoadPending: () => boolean = returnTrue;
/*@internal*/
sendLoadingProjectFinish = false;
/*@internal*/
constructor(configFileName: NormalizedPath,
projectService: ProjectService,
@@ -1371,12 +1376,15 @@ namespace ts.server {
result = this.projectService.reloadFileNamesOfConfiguredProject(this);
break;
case ConfigFileProgramReloadLevel.Full:
this.projectService.reloadConfiguredProject(this);
const reason = Debug.assertDefined(this.pendingReloadReason);
this.pendingReloadReason = undefined;
this.projectService.reloadConfiguredProject(this, reason);
result = true;
break;
default:
result = super.updateGraph();
}
this.projectService.sendProjectLoadingFinishEvent(this);
this.projectService.sendProjectTelemetry(this);
this.projectService.sendSurveyReady(this);
return result;
+24
View File
@@ -2452,6 +2452,30 @@ namespace ts.server.protocol {
openFiles: string[];
}
export type ProjectLoadingStartEventName = "projectLoadingStart";
export interface ProjectLoadingStartEvent extends Event {
event: ProjectLoadingStartEventName;
body: ProjectLoadingStartEventBody;
}
export interface ProjectLoadingStartEventBody {
/** name of the project */
projectName: string;
/** reason for loading */
reason: string;
}
export type ProjectLoadingFinishEventName = "projectLoadingFinish";
export interface ProjectLoadingFinishEvent extends Event {
event: ProjectLoadingFinishEventName;
body: ProjectLoadingFinishEventBody;
}
export interface ProjectLoadingFinishEventBody {
/** name of the project */
projectName: string;
}
export type SurveyReadyEventName = "surveyReady";
export interface SurveyReadyEvent extends Event {
+15 -5
View File
@@ -568,9 +568,19 @@ namespace ts.server {
const { openFiles } = event.data;
this.projectsUpdatedInBackgroundEvent(openFiles);
break;
case ProjectLoadingStartEvent:
const { project, reason } = event.data;
this.event<protocol.ProjectLoadingStartEventBody>(
{ projectName: project.getProjectName(), reason },
ProjectLoadingStartEvent);
break;
case ProjectLoadingFinishEvent:
const { project: finishProject } = event.data;
this.event<protocol.ProjectLoadingFinishEventBody>({ projectName: finishProject.getProjectName() }, ProjectLoadingStartEvent);
break;
case LargeFileReferencedEvent:
const { file, fileSize, maxFileSize } = event.data;
this.event<protocol.LargeFileReferencedEventBody>({ file, fileSize, maxFileSize }, "largeFileReferenced");
this.event<protocol.LargeFileReferencedEventBody>({ file, fileSize, maxFileSize }, LargeFileReferencedEvent);
break;
case ConfigFileDiagEvent:
const { triggerFile, configFileName: configFile, diagnostics } = event.data;
@@ -579,14 +589,14 @@ namespace ts.server {
triggerFile,
configFile,
diagnostics: bakedDiags
}, "configFileDiag");
}, ConfigFileDiagEvent);
break;
case SurveyReady:
const { surveyId } = event.data;
this.event<protocol.SurveyReadyEventBody>({ surveyId }, "surveyReady");
this.event<protocol.SurveyReadyEventBody>({ surveyId }, SurveyReady);
break;
case ProjectLanguageServiceStateEvent: {
const eventName: protocol.ProjectLanguageServiceStateEventName = "projectLanguageServiceState";
const eventName: protocol.ProjectLanguageServiceStateEventName = ProjectLanguageServiceStateEvent;
this.event<protocol.ProjectLanguageServiceStateEventBody>({
projectName: event.data.project.getProjectName(),
languageServiceEnabled: event.data.languageServiceEnabled
@@ -617,7 +627,7 @@ namespace ts.server {
// Send project changed event
this.event<protocol.ProjectsUpdatedInBackgroundEventBody>({
openFiles
}, "projectsUpdatedInBackground");
}, ProjectsUpdatedInBackgroundEvent);
}
}