Merge pull request #26197 from Microsoft/largeFileEvent

Send event on referencing large file
This commit is contained in:
Sheetal Nandi 2018-08-13 11:14:22 -07:00 committed by GitHub
commit f2011ce755
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 124 additions and 18 deletions

View file

@ -5,6 +5,7 @@ namespace ts.server {
// tslint:disable variable-name
export const ProjectsUpdatedInBackgroundEvent = "projectsUpdatedInBackground";
export const LargeFileReferencedEvent = "largeFileReferenced";
export const ConfigFileDiagEvent = "configFileDiag";
export const ProjectLanguageServiceStateEvent = "projectLanguageServiceState";
export const ProjectInfoTelemetryEvent = "projectInfo";
@ -16,6 +17,11 @@ namespace ts.server {
data: { openFiles: string[]; };
}
export interface LargeFileReferencedEvent {
eventName: typeof LargeFileReferencedEvent;
data: { file: string; fileSize: number; maxFileSize: number; };
}
export interface ConfigFileDiagEvent {
eventName: typeof ConfigFileDiagEvent;
data: { triggerFile: string, configFileName: string, diagnostics: ReadonlyArray<Diagnostic> };
@ -92,7 +98,7 @@ namespace ts.server {
readonly checkJs: boolean;
}
export type ProjectServiceEvent = ProjectsUpdatedInBackgroundEvent | ConfigFileDiagEvent | ProjectLanguageServiceStateEvent | ProjectInfoTelemetryEvent | OpenFileInfoTelemetryEvent;
export type ProjectServiceEvent = LargeFileReferencedEvent | ProjectsUpdatedInBackgroundEvent | ConfigFileDiagEvent | ProjectLanguageServiceStateEvent | ProjectInfoTelemetryEvent | OpenFileInfoTelemetryEvent;
export type ProjectServiceEventHandler = (event: ProjectServiceEvent) => void;
@ -645,6 +651,19 @@ namespace ts.server {
this.eventHandler(event);
}
/* @internal */
sendLargeFileReferencedEvent(file: string, fileSize: number) {
if (!this.eventHandler) {
return;
}
const event: LargeFileReferencedEvent = {
eventName: LargeFileReferencedEvent,
data: { file, fileSize, maxFileSize }
};
this.eventHandler(event);
}
/* @internal */
delayUpdateProjectGraphAndEnsureProjectStructureForOpenFiles(project: Project) {
this.delayUpdateProjectGraph(project);

View file

@ -2436,6 +2436,27 @@ namespace ts.server.protocol {
openFiles: string[];
}
export type LargeFileReferencedEventName = "largeFileReferenced";
export interface LargeFileReferencedEvent extends Event {
event: LargeFileReferencedEventName;
body: LargeFileReferencedEventBody;
}
export interface LargeFileReferencedEventBody {
/**
* name of the large file being loaded
*/
file: string;
/**
* size of the file
*/
fileSize: number;
/**
* max file size allowed on the server
*/
maxFileSize: number;
}
/**
* Arguments for reload request.
*/

View file

@ -39,7 +39,7 @@ namespace ts.server {
*/
private pendingReloadFromDisk: boolean;
constructor(private readonly host: ServerHost, private readonly fileName: NormalizedPath, initialVersion?: ScriptInfoVersion) {
constructor(private readonly host: ServerHost, private readonly fileName: NormalizedPath, initialVersion: ScriptInfoVersion | undefined, private readonly info: ScriptInfo) {
this.version = initialVersion || { svc: 0, text: 0 };
}
@ -164,9 +164,17 @@ namespace ts.server {
private getFileText(tempFileName?: string) {
let text: string;
const getText = () => text === undefined ? (text = this.host.readFile(tempFileName || this.fileName) || "") : text;
const size = this.host.getFileSize ? this.host.getFileSize(tempFileName || this.fileName) : getText().length;
return size > maxFileSize ? "" : getText();
const fileName = tempFileName || this.fileName;
const getText = () => text === undefined ? (text = this.host.readFile(fileName) || "") : text;
const fileSize = this.host.getFileSize ? this.host.getFileSize(fileName) : getText().length;
if (fileSize > maxFileSize) {
Debug.assert(!!this.info.containingProjects.length);
const service = this.info.containingProjects[0].projectService;
service.logger.info(`Skipped loading contents of large file ${fileName} for info ${this.info.fileName}: fileSize: ${fileSize}`);
this.info.containingProjects[0].projectService.sendLargeFileReferencedEvent(fileName, fileSize);
return "";
}
return getText();
}
private switchToScriptVersionCache(): ScriptVersionCache {
@ -248,7 +256,7 @@ namespace ts.server {
initialVersion?: ScriptInfoVersion) {
this.isDynamic = isDynamicFileName(fileName);
this.textStorage = new TextStorage(host, fileName, initialVersion);
this.textStorage = new TextStorage(host, fileName, initialVersion, this);
if (hasMixedContent || this.isDynamic) {
this.textStorage.reload("");
this.realpath = this.path;

View file

@ -559,6 +559,10 @@ namespace ts.server {
const { openFiles } = event.data;
this.projectsUpdatedInBackgroundEvent(openFiles);
break;
case LargeFileReferencedEvent:
const { file, fileSize, maxFileSize } = event.data;
this.event<protocol.LargeFileReferencedEventBody>({ file, fileSize, maxFileSize }, "largeFileReferenced");
break;
case ConfigFileDiagEvent:
const { triggerFile, configFileName: configFile, diagnostics } = event.data;
const bakedDiags = map(diagnostics, diagnostic => formatConfigFileDiag(diagnostic, /*includeFileName*/ true));

View file

@ -13,9 +13,9 @@ namespace ts.textStorage {
it("text based storage should be have exactly the same as script version cache", () => {
const host = projectSystem.createServerHost([f]);
const ts1 = new server.TextStorage(host, server.asNormalizedPath(f.path));
const ts2 = new server.TextStorage(host, server.asNormalizedPath(f.path));
// Since script info is not used in these tests, just cheat by passing undefined
const ts1 = new server.TextStorage(host, server.asNormalizedPath(f.path), /*initialVersion*/ undefined, /*info*/undefined!);
const ts2 = new server.TextStorage(host, server.asNormalizedPath(f.path), /*initialVersion*/ undefined, /*info*/undefined!);
ts1.useScriptVersionCache_TestOnly();
ts2.useText();
@ -48,7 +48,8 @@ namespace ts.textStorage {
it("should switch to script version cache if necessary", () => {
const host = projectSystem.createServerHost([f]);
const ts1 = new server.TextStorage(host, server.asNormalizedPath(f.path));
// Since script info is not used in these tests, just cheat by passing undefined
const ts1 = new server.TextStorage(host, server.asNormalizedPath(f.path), /*initialVersion*/ undefined, /*info*/undefined!);
ts1.getSnapshot();
assert.isTrue(!ts1.hasScriptVersionCache_TestOnly(), "should not have script version cache - 1");

View file

@ -2843,7 +2843,7 @@ namespace ts.projectSystem {
const session = createSession(host, {
canUseEvents: true,
eventHandler: e => {
if (e.eventName === server.ConfigFileDiagEvent || e.eventName === server.ProjectsUpdatedInBackgroundEvent || e.eventName === server.ProjectInfoTelemetryEvent || e.eventName === server.OpenFileInfoTelemetryEvent) {
if (e.eventName === server.ConfigFileDiagEvent || e.eventName === server.ProjectsUpdatedInBackgroundEvent || e.eventName === server.ProjectInfoTelemetryEvent || e.eventName === server.OpenFileInfoTelemetryEvent || e.eventName === server.LargeFileReferencedEvent) {
return;
}
assert.equal(e.eventName, server.ProjectLanguageServiceStateEvent);
@ -9028,6 +9028,27 @@ export const x = 10;`
fileSize: server.maxFileSize + 1
};
function createSessionWithEventHandler(host: TestServerHost) {
const largeFileReferencedEvents: server.LargeFileReferencedEvent[] = [];
const session = createSession(host, {
eventHandler: e => {
if (e.eventName === server.LargeFileReferencedEvent) {
largeFileReferencedEvents.push(e);
}
}
});
return { session, verifyLargeFileReferencedEvent };
function verifyLargeFileReferencedEvent() {
assert.equal(largeFileReferencedEvents.length, 1);
assert.deepEqual(largeFileReferencedEvents, [{
eventName: server.LargeFileReferencedEvent,
data: { file: largeFile.path, fileSize: largeFile.fileSize, maxFileSize: server.maxFileSize }
}]);
}
}
it("when large file is included by tsconfig", () => {
const file: File = {
path: `${projectRoot}/src/file.ts`,
@ -9039,13 +9060,15 @@ export const x = 10;`
};
const files = [file, largeFile, libFile, tsconfig];
const host = createServerHost(files);
const service = createProjectService(host);
service.openClientFile(file.path);
service.checkNumberOfProjects({ configuredProjects: 1 });
const { session, verifyLargeFileReferencedEvent } = createSessionWithEventHandler(host);
const service = session.getProjectService();
openFilesForSession([file], session);
checkNumberOfProjects(service, { configuredProjects: 1 });
const project = service.configuredProjects.get(tsconfig.path)!;
checkProjectActualFiles(project, [file.path, libFile.path, largeFile.path, tsconfig.path]);
const info = service.getScriptInfo(largeFile.path)!;
assert.equal(info.cacheSourceFile.sourceFile.text, "");
verifyLargeFileReferencedEvent();
});
it("when large file is included by module resolution", () => {
@ -9055,13 +9078,15 @@ export const x = 10;`
};
const files = [file, largeFile, libFile];
const host = createServerHost(files);
const service = createProjectService(host);
service.openClientFile(file.path);
service.checkNumberOfProjects({ inferredProjects: 1 });
const { session, verifyLargeFileReferencedEvent } = createSessionWithEventHandler(host);
const service = session.getProjectService();
openFilesForSession([file], session);
checkNumberOfProjects(service, { inferredProjects: 1 });
const project = service.inferredProjects[0];
checkProjectActualFiles(project, [file.path, libFile.path, largeFile.path]);
const info = service.getScriptInfo(largeFile.path)!;
assert.equal(info.cacheSourceFile.sourceFile.text, "");
verifyLargeFileReferencedEvent();
});
});

View file

@ -7660,6 +7660,25 @@ declare namespace ts.server.protocol {
*/
openFiles: string[];
}
type LargeFileReferencedEventName = "largeFileReferenced";
interface LargeFileReferencedEvent extends Event {
event: LargeFileReferencedEventName;
body: LargeFileReferencedEventBody;
}
interface LargeFileReferencedEventBody {
/**
* name of the large file being loaded
*/
file: string;
/**
* size of the file
*/
fileSize: number;
/**
* max file size allowed on the server
*/
maxFileSize: number;
}
/**
* Arguments for reload request.
*/
@ -8380,6 +8399,7 @@ declare namespace ts.server {
declare namespace ts.server {
const maxProgramSizeForNonTsFiles: number;
const ProjectsUpdatedInBackgroundEvent = "projectsUpdatedInBackground";
const LargeFileReferencedEvent = "largeFileReferenced";
const ConfigFileDiagEvent = "configFileDiag";
const ProjectLanguageServiceStateEvent = "projectLanguageServiceState";
const ProjectInfoTelemetryEvent = "projectInfo";
@ -8390,6 +8410,14 @@ declare namespace ts.server {
openFiles: string[];
};
}
interface LargeFileReferencedEvent {
eventName: typeof LargeFileReferencedEvent;
data: {
file: string;
fileSize: number;
maxFileSize: number;
};
}
interface ConfigFileDiagEvent {
eventName: typeof ConfigFileDiagEvent;
data: {
@ -8460,7 +8488,7 @@ declare namespace ts.server {
interface OpenFileInfo {
readonly checkJs: boolean;
}
type ProjectServiceEvent = ProjectsUpdatedInBackgroundEvent | ConfigFileDiagEvent | ProjectLanguageServiceStateEvent | ProjectInfoTelemetryEvent | OpenFileInfoTelemetryEvent;
type ProjectServiceEvent = LargeFileReferencedEvent | ProjectsUpdatedInBackgroundEvent | ConfigFileDiagEvent | ProjectLanguageServiceStateEvent | ProjectInfoTelemetryEvent | OpenFileInfoTelemetryEvent;
type ProjectServiceEventHandler = (event: ProjectServiceEvent) => void;
interface SafeList {
[name: string]: {