Skip to content

Commit 512ec04

Browse files
committed
[WIP] send\receive install typing requests
1 parent 959b6b6 commit 512ec04

5 files changed

Lines changed: 107 additions & 14 deletions

File tree

src/server/server.ts

Lines changed: 66 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,14 @@ namespace ts.server {
99
gzipSync(buf: Buffer): Buffer
1010
} = require("zlib");
1111

12+
interface NodeChildProcess {
13+
send(message: any, sendHandle?: any): void;
14+
}
15+
16+
const childProcess: {
17+
fork(modulePath: string): NodeChildProcess;
18+
} = require("child_process");
19+
1220
interface ReadLineOptions {
1321
input: NodeJS.ReadableStream;
1422
output?: NodeJS.WritableStream;
@@ -151,10 +159,65 @@ namespace ts.server {
151159
}
152160
}
153161

162+
class NodeTypingsInstaller implements ITypingsInstaller {
163+
private installer: NodeChildProcess;
164+
private session: Session;
165+
private cachePath: string;
166+
167+
constructor(private readonly logger: server.Logger) {
168+
switch (process.platform) {
169+
case "win32":
170+
this.cachePath = normalizeSlashes(combinePaths(process.env.LOCALAPPDATA || process.env.APPDATA, "Microsoft/TypeScript"));
171+
break;
172+
case "darwin":
173+
case "linux":
174+
// TODO:
175+
break;
176+
}
177+
}
178+
179+
bind(session: Session) {
180+
if (this.logger.hasLevel(LogLevel.requestTime)) {
181+
this.logger.info("Binding...")
182+
}
183+
184+
this.installer = childProcess.fork(combinePaths(__dirname, "typingsInstaller.js"));
185+
(<any>this.installer).on("message", (m: any) => this.handleMessage(m));
186+
}
187+
188+
enqueueInstallTypingsRequest(project: Project, typingOptions: TypingOptions): void {
189+
const request: InstallTypingsRequest = {
190+
projectName: project.getProjectName(),
191+
fileNames: project.getFileNames(),
192+
compilerOptions: project.getCompilerOptions(),
193+
typingOptions,
194+
projectRootPath: <Path>(project.projectKind === ProjectKind.Inferred ? "" : getDirectoryPath(project.getProjectName())), // TODO: fixme
195+
safeListPath: <Path>(combinePaths(process.cwd(), "typingSafeList.json")), // TODO: fixme
196+
packageNameToTypingLocation: {}, // TODO: fixme
197+
cachePath: this.cachePath
198+
};
199+
if (this.logger.hasLevel(LogLevel.verbose)) {
200+
this.logger.info(`Sending request: ${JSON.stringify(request)}`);
201+
}
202+
this.installer.send(request);
203+
}
204+
205+
C = 1;
206+
private handleMessage(response: InstallTypingsResponse) {
207+
if (this.logger.hasLevel(LogLevel.verbose)) {
208+
this.logger.info(`Received response: ${JSON.stringify(response)}`)
209+
}
210+
require("fs").appendFileSync("E:\\sources\\git\\tss.txt", this.C + " !!!::" + JSON.stringify(response) + "\r\n");
211+
this.C++;
212+
this.session.onTypingsInstalled(response);
213+
require("fs").appendFileSync("E:\\sources\\git\\tss.txt", this.C + " !!!::" + "done" + "\r\n");
214+
}
215+
}
216+
154217
class IOSession extends Session {
155-
constructor(host: ServerHost, cancellationToken: HostCancellationToken, useSingleInferredProject: boolean, logger: ts.server.Logger) {
156-
// TODO: fixme
157-
super(host, cancellationToken, useSingleInferredProject, undefined, Buffer.byteLength, maxUncompressedMessageSize, compress, process.hrtime, logger);
218+
constructor(host: ServerHost, cancellationToken: HostCancellationToken, useSingleInferredProject: boolean, logger: server.Logger) {
219+
super(host, cancellationToken, useSingleInferredProject, new NodeTypingsInstaller(logger), Buffer.byteLength, maxUncompressedMessageSize, compress, process.hrtime, logger);
220+
(<NodeTypingsInstaller>this.typingsInstaller).bind(this);
158221
}
159222

160223
exit() {

src/server/session.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ namespace ts.server {
143143
private host: ServerHost,
144144
cancellationToken: HostCancellationToken,
145145
useSingleInferredProject: boolean,
146-
typingsInstaller: ITypingsInstaller,
146+
protected readonly typingsInstaller: ITypingsInstaller,
147147
private byteLength: (buf: string, encoding?: string) => number,
148148
private maxUncompressedMessageSize: number,
149149
private compress: (s: string) => CompressedData,
@@ -1452,6 +1452,15 @@ namespace ts.server {
14521452
}
14531453
}
14541454

1455+
public onTypingsInstalled(response: InstallTypingsResponse) {
1456+
const project = this.projectService.findProject(response.projectName);
1457+
if (!project) {
1458+
return;
1459+
}
1460+
this.projectService.typingsCache.updateTypingsForProject(response.projectName, response.compilerOptions, response.typingOptions, response.typings);
1461+
project.updateGraph();
1462+
}
1463+
14551464
public onMessage(message: string) {
14561465
this.gcTimer.scheduleCollect();
14571466
let start: number[];

src/server/typingsCache.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
namespace ts.server {
44
export interface ITypingsInstaller {
5-
enqueueInstallTypingsRequest(p: Project): void;
5+
enqueueInstallTypingsRequest(p: Project, typingOptions: TypingOptions): void;
66
}
77

88
export const nullTypingsInstaller: ITypingsInstaller = {
@@ -12,7 +12,7 @@ namespace ts.server {
1212
class TypingsCacheEntry {
1313
readonly typingOptions: TypingOptions;
1414
readonly compilerOptions: CompilerOptions;
15-
readonly typings: Path[];
15+
readonly typings: string[];
1616
}
1717

1818
const emptyArray: any[] = [];
@@ -88,11 +88,19 @@ namespace ts.server {
8888

8989
const entry = this.perProjectCache[project.getProjectName()];
9090
if (!entry || typingOptionsChanged(typingOptions, entry.typingOptions) || compilerOptionsChanged(project.getCompilerOptions(), entry.compilerOptions)) {
91-
this.installer.enqueueInstallTypingsRequest(project);
91+
this.installer.enqueueInstallTypingsRequest(project, typingOptions);
9292
}
9393
return entry ? entry.typings : emptyArray;
9494
}
9595

96+
updateTypingsForProject(projectName: string, compilerOptions: CompilerOptions, typingOptions: TypingOptions, newTypings: string[]) {
97+
this.perProjectCache[projectName] = {
98+
compilerOptions,
99+
typingOptions,
100+
typings: newTypings
101+
};
102+
}
103+
96104
deleteTypingsForProject(project: Project) {
97105
delete this.perProjectCache[project.getProjectName()];
98106
}

src/server/typingsInstaller/nodeTypingsInstaller.ts

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
namespace ts.server.typingsInstaller {
55
export class NodeTypingsInstaller extends TypingsInstaller {
66
private execSync: { (command: string, options: { stdio: "ignore" }): any };
7-
private exec: { (command: string, options: {}, callback?: (error: Error, stdout: string, stderr: string) => void): any };
7+
private exec: { (command: string, options: { cwd: string }, callback?: (error: Error, stdout: string, stderr: string) => void): any };
88
constructor() {
99
super();
1010
this.execSync = require("child_process").execSync;
@@ -13,14 +13,14 @@ namespace ts.server.typingsInstaller {
1313

1414
init() {
1515
super.init();
16-
process.on("install", (req: InstallTypingsRequest) => {
16+
process.on("message", (req: InstallTypingsRequest) => {
1717
this.install(req);
1818
})
1919
}
2020

2121
protected isPackageInstalled(packageName: string) {
2222
try {
23-
this.execSync(`npm list --global --depth=1 ${name}`, { stdio: "ignore" });
23+
this.execSync(`npm list --global --depth=1 ${packageName}`, { stdio: "ignore" });
2424
return true;
2525
}
2626
catch (e) {
@@ -30,7 +30,7 @@ namespace ts.server.typingsInstaller {
3030

3131
protected installPackage(packageName: string) {
3232
try {
33-
this.execSync(`npm install --global ${name}`, { stdio: "ignore" });
33+
this.execSync(`npm install --global ${packageName}`, { stdio: "ignore" });
3434
return true;
3535
}
3636
catch (e) {
@@ -42,12 +42,17 @@ namespace ts.server.typingsInstaller {
4242
return sys;
4343
}
4444

45+
C = 1;
46+
4547
protected sendResponse(response: InstallTypingsResponse) {
48+
(<any>response).___id = [this.C];
49+
this.C++;
50+
log("sendResponse::" + JSON.stringify(response));
4651
process.send(response);
4752
}
4853

4954
protected runTsd(cachePath: string, typingsToInstall: string[], postInstallAction: (installedTypings: string[]) => void): void {
50-
this.exec(`tsd install ${typingsToInstall.join(" ")} -ros`, {}, (err, stdout, stderr) => {
55+
this.exec(`tsd install ${typingsToInstall.join(" ")} -ros`, { cwd: cachePath }, (err, stdout, stderr) => {
5156
const i = stdout.indexOf("running install");
5257
if (i < 0) {
5358
return;

src/server/typingsInstaller/typingsInstaller.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22
/// <reference path="../types.d.ts"/>
33

44
namespace ts.server.typingsInstaller {
5-
5+
export function log(s: string) {
6+
require("fs").appendFileSync("E:\\sources\\git\\installer.txt", s + "\r\n");
7+
}
68
const DefaultTsdSettings = JSON.stringify({
79
version: "v4",
810
repo: "DefinitelyTyped/DefinitelyTyped",
@@ -20,13 +22,15 @@ namespace ts.server.typingsInstaller {
2022
if (!this.isTsdInstalled) {
2123
this.isTsdInstalled = this.installPackage("tsd");
2224
}
25+
log(`start ${this.isTsdInstalled}`);
2326
}
2427

2528
install(req: InstallTypingsRequest) {
2629
if (!this.isTsdInstalled) {
2730
return;
2831
}
2932

33+
log(`install ${JSON.stringify(req)}`);
3034
const discoverTypingsResult = JsTyping.discoverTypings(
3135
this.getInstallTypingHost(),
3236
req.fileNames,
@@ -36,6 +40,7 @@ namespace ts.server.typingsInstaller {
3640
req.typingOptions,
3741
req.compilerOptions);
3842

43+
log(`install ${JSON.stringify(discoverTypingsResult)}`);
3944
// respond with whatever cached typings we have now
4045
this.sendResponse(this.createResponse(req, discoverTypingsResult.cachedTypingPaths));
4146
// start watching files
@@ -46,6 +51,7 @@ namespace ts.server.typingsInstaller {
4651

4752
private installTypings(req: InstallTypingsRequest, currentlyCachedTypings: string[], typingsToInstall: string[]) {
4853
typingsToInstall = filter(typingsToInstall, x => !hasProperty(this.missingTypings, x));
54+
log(`install ${JSON.stringify(typingsToInstall)}`);
4955
if (typingsToInstall.length === 0) {
5056
return;
5157
}
@@ -57,9 +63,11 @@ namespace ts.server.typingsInstaller {
5763
host.writeFile(tsdPath, DefaultTsdSettings);
5864
}
5965

60-
this.runTsd(tsdPath, typingsToInstall, installedTypings => {
66+
this.runTsd(req.cachePath, typingsToInstall, installedTypings => {
6167
// TODO: record new missing package names
6268
// TODO: watch project directory
69+
installedTypings = installedTypings.map(x => getNormalizedAbsolutePath(x, req.cachePath));
70+
log(`include ${JSON.stringify(installedTypings)}`);
6371
this.sendResponse(this.createResponse(req, currentlyCachedTypings.concat(installedTypings)));
6472
});
6573
}

0 commit comments

Comments
 (0)