mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user