Skip to content

Commit 4ffdea8

Browse files
authored
Ports #12051 and #12032 into master (#12090)
* use local registry to check if typings package exist (#12014) use local registry to check if typings package exist * enable sending telemetry events to tsserver client (#12035) enable sending telemetry events
1 parent d16aa30 commit 4ffdea8

15 files changed

+412
-322
lines changed

Jakefile.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,7 @@ var servicesSources = [
171171

172172
var serverCoreSources = [
173173
"types.d.ts",
174+
"shared.ts",
174175
"utilities.ts",
175176
"scriptVersionCache.ts",
176177
"typingsCache.ts",
@@ -193,6 +194,7 @@ var cancellationTokenSources = [
193194

194195
var typingsInstallerSources = [
195196
"../types.d.ts",
197+
"../shared.ts",
196198
"typingsInstaller.ts",
197199
"nodeTypingsInstaller.ts"
198200
].map(function (f) {

src/harness/unittests/tsserverProjectSystem.ts

Lines changed: 14 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ namespace ts.projectSystem {
1818
};
1919

2020
export interface PostExecAction {
21-
readonly requestKind: TI.RequestKind;
2221
readonly success: boolean;
2322
readonly callback: TI.RequestCompletedAction;
2423
}
@@ -47,9 +46,14 @@ namespace ts.projectSystem {
4746

4847
export class TestTypingsInstaller extends TI.TypingsInstaller implements server.ITypingsInstaller {
4948
protected projectService: server.ProjectService;
50-
constructor(readonly globalTypingsCacheLocation: string, throttleLimit: number, readonly installTypingHost: server.ServerHost, log?: TI.Log) {
51-
super(globalTypingsCacheLocation, safeList.path, throttleLimit, log);
52-
this.init();
49+
constructor(
50+
readonly globalTypingsCacheLocation: string,
51+
throttleLimit: number,
52+
installTypingHost: server.ServerHost,
53+
readonly typesRegistry = createMap<void>(),
54+
telemetryEnabled?: boolean,
55+
log?: TI.Log) {
56+
super(installTypingHost, globalTypingsCacheLocation, safeList.path, throttleLimit, telemetryEnabled, log);
5357
}
5458

5559
safeFileList = safeList.path;
@@ -63,9 +67,8 @@ namespace ts.projectSystem {
6367
}
6468
}
6569

66-
checkPendingCommands(expected: TI.RequestKind[]) {
67-
assert.equal(this.postExecActions.length, expected.length, `Expected ${expected.length} post install actions`);
68-
this.postExecActions.forEach((act, i) => assert.equal(act.requestKind, expected[i], "Unexpected post install action"));
70+
checkPendingCommands(expectedCount: number) {
71+
assert.equal(this.postExecActions.length, expectedCount, `Expected ${expectedCount} post install actions`);
6972
}
7073

7174
onProjectClosed() {
@@ -79,15 +82,8 @@ namespace ts.projectSystem {
7982
return this.installTypingHost;
8083
}
8184

82-
executeRequest(requestKind: TI.RequestKind, _requestId: number, _args: string[], _cwd: string, cb: TI.RequestCompletedAction): void {
83-
switch (requestKind) {
84-
case TI.NpmViewRequest:
85-
case TI.NpmInstallRequest:
86-
break;
87-
default:
88-
assert.isTrue(false, `request ${requestKind} is not supported`);
89-
}
90-
this.addPostExecAction(requestKind, "success", cb);
85+
installWorker(_requestId: number, _args: string[], _cwd: string, cb: TI.RequestCompletedAction): void {
86+
this.addPostExecAction("success", cb);
9187
}
9288

9389
sendResponse(response: server.SetTypings | server.InvalidateCachedTypings) {
@@ -99,12 +95,11 @@ namespace ts.projectSystem {
9995
this.install(request);
10096
}
10197

102-
addPostExecAction(requestKind: TI.RequestKind, stdout: string | string[], cb: TI.RequestCompletedAction) {
98+
addPostExecAction(stdout: string | string[], cb: TI.RequestCompletedAction) {
10399
const out = typeof stdout === "string" ? stdout : createNpmPackageJsonString(stdout);
104100
const action: PostExecAction = {
105101
success: !!out,
106-
callback: cb,
107-
requestKind
102+
callback: cb
108103
};
109104
this.postExecActions.push(action);
110105
}

src/harness/unittests/typingsInstaller.ts

Lines changed: 141 additions & 122 deletions
Large diffs are not rendered by default.

src/server/editorServices.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -286,10 +286,10 @@ namespace ts.server {
286286
return;
287287
}
288288
switch (response.kind) {
289-
case "set":
289+
case ActionSet:
290290
this.typingsCache.updateTypingsForProject(response.projectName, response.compilerOptions, response.typingOptions, response.unresolvedImports, response.typings);
291291
break;
292-
case "invalidate":
292+
case ActionInvalidate:
293293
this.typingsCache.deleteTypingsForProject(response.projectName);
294294
break;
295295
}

src/server/protocol.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2057,6 +2057,32 @@ namespace ts.server.protocol {
20572057
childItems?: NavigationTree[];
20582058
}
20592059

2060+
export type TelemetryEventName = "telemetry";
2061+
2062+
export interface TelemetryEvent extends Event {
2063+
event: TelemetryEventName;
2064+
body: TelemetryEventBody;
2065+
}
2066+
2067+
export interface TelemetryEventBody {
2068+
telemetryEventName: string;
2069+
payload: any;
2070+
}
2071+
2072+
export type TypingsInstalledTelemetryEventName = "typingsInstalled";
2073+
2074+
export interface TypingsInstalledTelemetryEventBody extends TelemetryEventBody {
2075+
telemetryEventName: TypingsInstalledTelemetryEventName;
2076+
payload: TypingsInstalledTelemetryEventPayload;
2077+
}
2078+
2079+
export interface TypingsInstalledTelemetryEventPayload {
2080+
/**
2081+
* Comma separated list of installed typing packages
2082+
*/
2083+
installedPackages: string;
2084+
}
2085+
20602086
export interface NavBarResponse extends Response {
20612087
body?: NavigationBarItem[];
20622088
}

src/server/server.ts

Lines changed: 54 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
/// <reference types="node" />
2+
/// <reference path="shared.ts" />
23
/// <reference path="session.ts" />
34
// used in fs.writeSync
45
/* tslint:disable:no-null-keyword */
@@ -196,8 +197,10 @@ namespace ts.server {
196197
private socket: NodeSocket;
197198
private projectService: ProjectService;
198199
private throttledOperations: ThrottledOperations;
200+
private telemetrySender: EventSender;
199201

200202
constructor(
203+
private readonly telemetryEnabled: boolean,
201204
private readonly logger: server.Logger,
202205
host: ServerHost,
203206
eventPort: number,
@@ -226,15 +229,22 @@ namespace ts.server {
226229
this.socket.write(formatMessage({ seq, type: "event", event, body }, this.logger, Buffer.byteLength, this.newLine), "utf8");
227230
}
228231

232+
setTelemetrySender(telemetrySender: EventSender) {
233+
this.telemetrySender = telemetrySender;
234+
}
235+
229236
attach(projectService: ProjectService) {
230237
this.projectService = projectService;
231238
if (this.logger.hasLevel(LogLevel.requestTime)) {
232239
this.logger.info("Binding...");
233240
}
234241

235-
const args: string[] = ["--globalTypingsCacheLocation", this.globalTypingsCacheLocation];
242+
const args: string[] = [Arguments.GlobalCacheLocation, this.globalTypingsCacheLocation];
243+
if (this.telemetryEnabled) {
244+
args.push(Arguments.EnableTelemetry);
245+
}
236246
if (this.logger.loggingEnabled() && this.logger.getLogFileName()) {
237-
args.push("--logFile", combinePaths(getDirectoryPath(normalizeSlashes(this.logger.getLogFileName())), `ti-${process.pid}.log`));
247+
args.push(Arguments.LogFile, combinePaths(getDirectoryPath(normalizeSlashes(this.logger.getLogFileName())), `ti-${process.pid}.log`));
238248
}
239249
const execArgv: string[] = [];
240250
{
@@ -280,12 +290,25 @@ namespace ts.server {
280290
});
281291
}
282292

283-
private handleMessage(response: SetTypings | InvalidateCachedTypings) {
293+
private handleMessage(response: SetTypings | InvalidateCachedTypings | TypingsInstallEvent) {
284294
if (this.logger.hasLevel(LogLevel.verbose)) {
285295
this.logger.info(`Received response: ${JSON.stringify(response)}`);
286296
}
297+
if (response.kind === EventInstall) {
298+
if (this.telemetrySender) {
299+
const body: protocol.TypingsInstalledTelemetryEventBody = {
300+
telemetryEventName: "typingsInstalled",
301+
payload: {
302+
installedPackages: response.packagesToInstall.join(",")
303+
}
304+
};
305+
const eventName: protocol.TelemetryEventName = "telemetry";
306+
this.telemetrySender.event(body, eventName);
307+
}
308+
return;
309+
}
287310
this.projectService.updateTypingsForProject(response);
288-
if (response.kind == "set" && this.socket) {
311+
if (response.kind == ActionSet && this.socket) {
289312
this.sendEvent(0, "setTypings", response);
290313
}
291314
}
@@ -300,18 +323,25 @@ namespace ts.server {
300323
useSingleInferredProject: boolean,
301324
disableAutomaticTypingAcquisition: boolean,
302325
globalTypingsCacheLocation: string,
326+
telemetryEnabled: boolean,
303327
logger: server.Logger) {
304-
super(
305-
host,
306-
cancellationToken,
307-
useSingleInferredProject,
308-
disableAutomaticTypingAcquisition
309-
? nullTypingsInstaller
310-
: new NodeTypingsInstaller(logger, host, installerEventPort, globalTypingsCacheLocation, host.newLine),
311-
Buffer.byteLength,
312-
process.hrtime,
313-
logger,
314-
canUseEvents);
328+
const typingsInstaller = disableAutomaticTypingAcquisition
329+
? undefined
330+
: new NodeTypingsInstaller(telemetryEnabled, logger, host, installerEventPort, globalTypingsCacheLocation, host.newLine);
331+
332+
super(
333+
host,
334+
cancellationToken,
335+
useSingleInferredProject,
336+
typingsInstaller || nullTypingsInstaller,
337+
Buffer.byteLength,
338+
process.hrtime,
339+
logger,
340+
canUseEvents);
341+
342+
if (telemetryEnabled && typingsInstaller) {
343+
typingsInstaller.setTelemetrySender(this);
344+
}
315345
}
316346

317347
exit() {
@@ -538,17 +568,17 @@ namespace ts.server {
538568

539569
let eventPort: number;
540570
{
541-
const index = sys.args.indexOf("--eventPort");
542-
if (index >= 0 && index < sys.args.length - 1) {
543-
const v = parseInt(sys.args[index + 1]);
544-
if (!isNaN(v)) {
545-
eventPort = v;
546-
}
571+
const str = findArgument("--eventPort");
572+
const v = str && parseInt(str);
573+
if (!isNaN(v)) {
574+
eventPort = v;
547575
}
548576
}
549577

550-
const useSingleInferredProject = sys.args.indexOf("--useSingleInferredProject") >= 0;
551-
const disableAutomaticTypingAcquisition = sys.args.indexOf("--disableAutomaticTypingAcquisition") >= 0;
578+
const useSingleInferredProject = hasArgument("--useSingleInferredProject");
579+
const disableAutomaticTypingAcquisition = hasArgument("--disableAutomaticTypingAcquisition");
580+
const telemetryEnabled = hasArgument(Arguments.EnableTelemetry);
581+
552582
const ioSession = new IOSession(
553583
sys,
554584
cancellationToken,
@@ -557,6 +587,7 @@ namespace ts.server {
557587
useSingleInferredProject,
558588
disableAutomaticTypingAcquisition,
559589
getGlobalTypingsCacheLocation(),
590+
telemetryEnabled,
560591
logger);
561592
process.on("uncaughtException", function (err: Error) {
562593
ioSession.logError(err, "unknown");

src/server/session.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,10 @@ namespace ts.server {
7373
project: Project;
7474
}
7575

76+
export interface EventSender {
77+
event(payload: any, eventName: string): void;
78+
}
79+
7680
function allEditsBeforePos(edits: ts.TextChange[], pos: number) {
7781
for (const edit of edits) {
7882
if (textSpanEnd(edit.span) >= pos) {
@@ -165,7 +169,7 @@ namespace ts.server {
165169
return `Content-Length: ${1 + len}\r\n\r\n${json}${newLine}`;
166170
}
167171

168-
export class Session {
172+
export class Session implements EventSender {
169173
private readonly gcTimer: GcTimer;
170174
protected projectService: ProjectService;
171175
private errorTimer: any; /*NodeJS.Timer | number*/

src/server/shared.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/// <reference path="types.d.ts" />
2+
3+
namespace ts.server {
4+
export const ActionSet: ActionSet = "action::set";
5+
export const ActionInvalidate: ActionInvalidate = "action::invalidate";
6+
export const EventInstall: EventInstall = "event::install";
7+
8+
export namespace Arguments {
9+
export const GlobalCacheLocation = "--globalTypingsCacheLocation";
10+
export const LogFile = "--logFile";
11+
export const EnableTelemetry = "--enableTelemetry";
12+
}
13+
14+
export function hasArgument(argumentName: string) {
15+
return sys.args.indexOf(argumentName) >= 0;
16+
}
17+
18+
export function findArgument(argumentName: string) {
19+
const index = sys.args.indexOf(argumentName);
20+
return index >= 0 && index < sys.args.length - 1
21+
? sys.args[index + 1]
22+
: undefined;
23+
}
24+
}

src/server/tsconfig.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
"files": [
1919
"../services/shims.ts",
2020
"../services/utilities.ts",
21+
"shared.ts",
2122
"utilities.ts",
2223
"scriptVersionCache.ts",
2324
"scriptInfo.ts",

src/server/tsconfig.library.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
"files": [
1616
"../services/shims.ts",
1717
"../services/utilities.ts",
18+
"shared.ts",
1819
"utilities.ts",
1920
"scriptVersionCache.ts",
2021
"scriptInfo.ts",

src/server/types.d.ts

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -41,23 +41,33 @@ declare namespace ts.server {
4141
readonly kind: "closeProject";
4242
}
4343

44-
export type SetRequest = "set";
45-
export type InvalidateRequest = "invalidate";
44+
export type ActionSet = "action::set";
45+
export type ActionInvalidate = "action::invalidate";
46+
export type EventInstall = "event::install";
47+
4648
export interface TypingInstallerResponse {
49+
readonly kind: ActionSet | ActionInvalidate | EventInstall;
50+
}
51+
52+
export interface ProjectResponse extends TypingInstallerResponse {
4753
readonly projectName: string;
48-
readonly kind: SetRequest | InvalidateRequest;
4954
}
5055

51-
export interface SetTypings extends TypingInstallerResponse {
56+
export interface SetTypings extends ProjectResponse {
5257
readonly typingOptions: ts.TypingOptions;
5358
readonly compilerOptions: ts.CompilerOptions;
5459
readonly typings: string[];
5560
readonly unresolvedImports: SortedReadonlyArray<string>;
56-
readonly kind: SetRequest;
61+
readonly kind: ActionSet;
62+
}
63+
64+
export interface InvalidateCachedTypings extends ProjectResponse {
65+
readonly kind: ActionInvalidate;
5766
}
5867

59-
export interface InvalidateCachedTypings extends TypingInstallerResponse {
60-
readonly kind: InvalidateRequest;
68+
export interface TypingsInstallEvent extends TypingInstallerResponse {
69+
readonly packagesToInstall: ReadonlyArray<string>;
70+
readonly kind: EventInstall;
6171
}
6272

6373
export interface InstallTypingHost extends JsTyping.TypingResolutionHost {

0 commit comments

Comments
 (0)