Skip to content

Commit f2011ce

Browse files
authored
Merge pull request #26197 from Microsoft/largeFileEvent
Send event on referencing large file
2 parents 2b83b67 + 1e5e618 commit f2011ce

File tree

7 files changed

+124
-18
lines changed

7 files changed

+124
-18
lines changed

src/server/editorServices.ts

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ namespace ts.server {
55

66
// tslint:disable variable-name
77
export const ProjectsUpdatedInBackgroundEvent = "projectsUpdatedInBackground";
8+
export const LargeFileReferencedEvent = "largeFileReferenced";
89
export const ConfigFileDiagEvent = "configFileDiag";
910
export const ProjectLanguageServiceStateEvent = "projectLanguageServiceState";
1011
export const ProjectInfoTelemetryEvent = "projectInfo";
@@ -16,6 +17,11 @@ namespace ts.server {
1617
data: { openFiles: string[]; };
1718
}
1819

20+
export interface LargeFileReferencedEvent {
21+
eventName: typeof LargeFileReferencedEvent;
22+
data: { file: string; fileSize: number; maxFileSize: number; };
23+
}
24+
1925
export interface ConfigFileDiagEvent {
2026
eventName: typeof ConfigFileDiagEvent;
2127
data: { triggerFile: string, configFileName: string, diagnostics: ReadonlyArray<Diagnostic> };
@@ -92,7 +98,7 @@ namespace ts.server {
9298
readonly checkJs: boolean;
9399
}
94100

95-
export type ProjectServiceEvent = ProjectsUpdatedInBackgroundEvent | ConfigFileDiagEvent | ProjectLanguageServiceStateEvent | ProjectInfoTelemetryEvent | OpenFileInfoTelemetryEvent;
101+
export type ProjectServiceEvent = LargeFileReferencedEvent | ProjectsUpdatedInBackgroundEvent | ConfigFileDiagEvent | ProjectLanguageServiceStateEvent | ProjectInfoTelemetryEvent | OpenFileInfoTelemetryEvent;
96102

97103
export type ProjectServiceEventHandler = (event: ProjectServiceEvent) => void;
98104

@@ -645,6 +651,19 @@ namespace ts.server {
645651
this.eventHandler(event);
646652
}
647653

654+
/* @internal */
655+
sendLargeFileReferencedEvent(file: string, fileSize: number) {
656+
if (!this.eventHandler) {
657+
return;
658+
}
659+
660+
const event: LargeFileReferencedEvent = {
661+
eventName: LargeFileReferencedEvent,
662+
data: { file, fileSize, maxFileSize }
663+
};
664+
this.eventHandler(event);
665+
}
666+
648667
/* @internal */
649668
delayUpdateProjectGraphAndEnsureProjectStructureForOpenFiles(project: Project) {
650669
this.delayUpdateProjectGraph(project);

src/server/protocol.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2436,6 +2436,27 @@ namespace ts.server.protocol {
24362436
openFiles: string[];
24372437
}
24382438

2439+
export type LargeFileReferencedEventName = "largeFileReferenced";
2440+
export interface LargeFileReferencedEvent extends Event {
2441+
event: LargeFileReferencedEventName;
2442+
body: LargeFileReferencedEventBody;
2443+
}
2444+
2445+
export interface LargeFileReferencedEventBody {
2446+
/**
2447+
* name of the large file being loaded
2448+
*/
2449+
file: string;
2450+
/**
2451+
* size of the file
2452+
*/
2453+
fileSize: number;
2454+
/**
2455+
* max file size allowed on the server
2456+
*/
2457+
maxFileSize: number;
2458+
}
2459+
24392460
/**
24402461
* Arguments for reload request.
24412462
*/

src/server/scriptInfo.ts

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ namespace ts.server {
3939
*/
4040
private pendingReloadFromDisk: boolean;
4141

42-
constructor(private readonly host: ServerHost, private readonly fileName: NormalizedPath, initialVersion?: ScriptInfoVersion) {
42+
constructor(private readonly host: ServerHost, private readonly fileName: NormalizedPath, initialVersion: ScriptInfoVersion | undefined, private readonly info: ScriptInfo) {
4343
this.version = initialVersion || { svc: 0, text: 0 };
4444
}
4545

@@ -164,9 +164,17 @@ namespace ts.server {
164164

165165
private getFileText(tempFileName?: string) {
166166
let text: string;
167-
const getText = () => text === undefined ? (text = this.host.readFile(tempFileName || this.fileName) || "") : text;
168-
const size = this.host.getFileSize ? this.host.getFileSize(tempFileName || this.fileName) : getText().length;
169-
return size > maxFileSize ? "" : getText();
167+
const fileName = tempFileName || this.fileName;
168+
const getText = () => text === undefined ? (text = this.host.readFile(fileName) || "") : text;
169+
const fileSize = this.host.getFileSize ? this.host.getFileSize(fileName) : getText().length;
170+
if (fileSize > maxFileSize) {
171+
Debug.assert(!!this.info.containingProjects.length);
172+
const service = this.info.containingProjects[0].projectService;
173+
service.logger.info(`Skipped loading contents of large file ${fileName} for info ${this.info.fileName}: fileSize: ${fileSize}`);
174+
this.info.containingProjects[0].projectService.sendLargeFileReferencedEvent(fileName, fileSize);
175+
return "";
176+
}
177+
return getText();
170178
}
171179

172180
private switchToScriptVersionCache(): ScriptVersionCache {
@@ -248,7 +256,7 @@ namespace ts.server {
248256
initialVersion?: ScriptInfoVersion) {
249257
this.isDynamic = isDynamicFileName(fileName);
250258

251-
this.textStorage = new TextStorage(host, fileName, initialVersion);
259+
this.textStorage = new TextStorage(host, fileName, initialVersion, this);
252260
if (hasMixedContent || this.isDynamic) {
253261
this.textStorage.reload("");
254262
this.realpath = this.path;

src/server/session.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -559,6 +559,10 @@ namespace ts.server {
559559
const { openFiles } = event.data;
560560
this.projectsUpdatedInBackgroundEvent(openFiles);
561561
break;
562+
case LargeFileReferencedEvent:
563+
const { file, fileSize, maxFileSize } = event.data;
564+
this.event<protocol.LargeFileReferencedEventBody>({ file, fileSize, maxFileSize }, "largeFileReferenced");
565+
break;
562566
case ConfigFileDiagEvent:
563567
const { triggerFile, configFileName: configFile, diagnostics } = event.data;
564568
const bakedDiags = map(diagnostics, diagnostic => formatConfigFileDiag(diagnostic, /*includeFileName*/ true));

src/testRunner/unittests/textStorage.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@ namespace ts.textStorage {
1313
it("text based storage should be have exactly the same as script version cache", () => {
1414

1515
const host = projectSystem.createServerHost([f]);
16-
17-
const ts1 = new server.TextStorage(host, server.asNormalizedPath(f.path));
18-
const ts2 = new server.TextStorage(host, server.asNormalizedPath(f.path));
16+
// Since script info is not used in these tests, just cheat by passing undefined
17+
const ts1 = new server.TextStorage(host, server.asNormalizedPath(f.path), /*initialVersion*/ undefined, /*info*/undefined!);
18+
const ts2 = new server.TextStorage(host, server.asNormalizedPath(f.path), /*initialVersion*/ undefined, /*info*/undefined!);
1919

2020
ts1.useScriptVersionCache_TestOnly();
2121
ts2.useText();
@@ -48,7 +48,8 @@ namespace ts.textStorage {
4848

4949
it("should switch to script version cache if necessary", () => {
5050
const host = projectSystem.createServerHost([f]);
51-
const ts1 = new server.TextStorage(host, server.asNormalizedPath(f.path));
51+
// Since script info is not used in these tests, just cheat by passing undefined
52+
const ts1 = new server.TextStorage(host, server.asNormalizedPath(f.path), /*initialVersion*/ undefined, /*info*/undefined!);
5253

5354
ts1.getSnapshot();
5455
assert.isTrue(!ts1.hasScriptVersionCache_TestOnly(), "should not have script version cache - 1");

src/testRunner/unittests/tsserverProjectSystem.ts

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2843,7 +2843,7 @@ namespace ts.projectSystem {
28432843
const session = createSession(host, {
28442844
canUseEvents: true,
28452845
eventHandler: e => {
2846-
if (e.eventName === server.ConfigFileDiagEvent || e.eventName === server.ProjectsUpdatedInBackgroundEvent || e.eventName === server.ProjectInfoTelemetryEvent || e.eventName === server.OpenFileInfoTelemetryEvent) {
2846+
if (e.eventName === server.ConfigFileDiagEvent || e.eventName === server.ProjectsUpdatedInBackgroundEvent || e.eventName === server.ProjectInfoTelemetryEvent || e.eventName === server.OpenFileInfoTelemetryEvent || e.eventName === server.LargeFileReferencedEvent) {
28472847
return;
28482848
}
28492849
assert.equal(e.eventName, server.ProjectLanguageServiceStateEvent);
@@ -9028,6 +9028,27 @@ export const x = 10;`
90289028
fileSize: server.maxFileSize + 1
90299029
};
90309030

9031+
function createSessionWithEventHandler(host: TestServerHost) {
9032+
const largeFileReferencedEvents: server.LargeFileReferencedEvent[] = [];
9033+
const session = createSession(host, {
9034+
eventHandler: e => {
9035+
if (e.eventName === server.LargeFileReferencedEvent) {
9036+
largeFileReferencedEvents.push(e);
9037+
}
9038+
}
9039+
});
9040+
9041+
return { session, verifyLargeFileReferencedEvent };
9042+
9043+
function verifyLargeFileReferencedEvent() {
9044+
assert.equal(largeFileReferencedEvents.length, 1);
9045+
assert.deepEqual(largeFileReferencedEvents, [{
9046+
eventName: server.LargeFileReferencedEvent,
9047+
data: { file: largeFile.path, fileSize: largeFile.fileSize, maxFileSize: server.maxFileSize }
9048+
}]);
9049+
}
9050+
}
9051+
90319052
it("when large file is included by tsconfig", () => {
90329053
const file: File = {
90339054
path: `${projectRoot}/src/file.ts`,
@@ -9039,13 +9060,15 @@ export const x = 10;`
90399060
};
90409061
const files = [file, largeFile, libFile, tsconfig];
90419062
const host = createServerHost(files);
9042-
const service = createProjectService(host);
9043-
service.openClientFile(file.path);
9044-
service.checkNumberOfProjects({ configuredProjects: 1 });
9063+
const { session, verifyLargeFileReferencedEvent } = createSessionWithEventHandler(host);
9064+
const service = session.getProjectService();
9065+
openFilesForSession([file], session);
9066+
checkNumberOfProjects(service, { configuredProjects: 1 });
90459067
const project = service.configuredProjects.get(tsconfig.path)!;
90469068
checkProjectActualFiles(project, [file.path, libFile.path, largeFile.path, tsconfig.path]);
90479069
const info = service.getScriptInfo(largeFile.path)!;
90489070
assert.equal(info.cacheSourceFile.sourceFile.text, "");
9071+
verifyLargeFileReferencedEvent();
90499072
});
90509073

90519074
it("when large file is included by module resolution", () => {
@@ -9055,13 +9078,15 @@ export const x = 10;`
90559078
};
90569079
const files = [file, largeFile, libFile];
90579080
const host = createServerHost(files);
9058-
const service = createProjectService(host);
9059-
service.openClientFile(file.path);
9060-
service.checkNumberOfProjects({ inferredProjects: 1 });
9081+
const { session, verifyLargeFileReferencedEvent } = createSessionWithEventHandler(host);
9082+
const service = session.getProjectService();
9083+
openFilesForSession([file], session);
9084+
checkNumberOfProjects(service, { inferredProjects: 1 });
90619085
const project = service.inferredProjects[0];
90629086
checkProjectActualFiles(project, [file.path, libFile.path, largeFile.path]);
90639087
const info = service.getScriptInfo(largeFile.path)!;
90649088
assert.equal(info.cacheSourceFile.sourceFile.text, "");
9089+
verifyLargeFileReferencedEvent();
90659090
});
90669091
});
90679092

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

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7660,6 +7660,25 @@ declare namespace ts.server.protocol {
76607660
*/
76617661
openFiles: string[];
76627662
}
7663+
type LargeFileReferencedEventName = "largeFileReferenced";
7664+
interface LargeFileReferencedEvent extends Event {
7665+
event: LargeFileReferencedEventName;
7666+
body: LargeFileReferencedEventBody;
7667+
}
7668+
interface LargeFileReferencedEventBody {
7669+
/**
7670+
* name of the large file being loaded
7671+
*/
7672+
file: string;
7673+
/**
7674+
* size of the file
7675+
*/
7676+
fileSize: number;
7677+
/**
7678+
* max file size allowed on the server
7679+
*/
7680+
maxFileSize: number;
7681+
}
76637682
/**
76647683
* Arguments for reload request.
76657684
*/
@@ -8380,6 +8399,7 @@ declare namespace ts.server {
83808399
declare namespace ts.server {
83818400
const maxProgramSizeForNonTsFiles: number;
83828401
const ProjectsUpdatedInBackgroundEvent = "projectsUpdatedInBackground";
8402+
const LargeFileReferencedEvent = "largeFileReferenced";
83838403
const ConfigFileDiagEvent = "configFileDiag";
83848404
const ProjectLanguageServiceStateEvent = "projectLanguageServiceState";
83858405
const ProjectInfoTelemetryEvent = "projectInfo";
@@ -8390,6 +8410,14 @@ declare namespace ts.server {
83908410
openFiles: string[];
83918411
};
83928412
}
8413+
interface LargeFileReferencedEvent {
8414+
eventName: typeof LargeFileReferencedEvent;
8415+
data: {
8416+
file: string;
8417+
fileSize: number;
8418+
maxFileSize: number;
8419+
};
8420+
}
83938421
interface ConfigFileDiagEvent {
83948422
eventName: typeof ConfigFileDiagEvent;
83958423
data: {
@@ -8460,7 +8488,7 @@ declare namespace ts.server {
84608488
interface OpenFileInfo {
84618489
readonly checkJs: boolean;
84628490
}
8463-
type ProjectServiceEvent = ProjectsUpdatedInBackgroundEvent | ConfigFileDiagEvent | ProjectLanguageServiceStateEvent | ProjectInfoTelemetryEvent | OpenFileInfoTelemetryEvent;
8491+
type ProjectServiceEvent = LargeFileReferencedEvent | ProjectsUpdatedInBackgroundEvent | ConfigFileDiagEvent | ProjectLanguageServiceStateEvent | ProjectInfoTelemetryEvent | OpenFileInfoTelemetryEvent;
84648492
type ProjectServiceEventHandler = (event: ProjectServiceEvent) => void;
84658493
interface SafeList {
84668494
[name: string]: {

0 commit comments

Comments
 (0)