diff --git a/Gulpfile.ts b/Gulpfile.ts
index d7e20a557fd78..054e99c80037e 100644
--- a/Gulpfile.ts
+++ b/Gulpfile.ts
@@ -177,7 +177,7 @@ for (const i in libraryTargets) {
const configureNightlyJs = path.join(scriptsDirectory, "configureNightly.js");
const configureNightlyTs = path.join(scriptsDirectory, "configureNightly.ts");
const packageJson = "package.json";
-const programTs = path.join(compilerDirectory, "program.ts");
+const versionFile = path.join(compilerDirectory, "core.ts");
function needsUpdate(source: string | string[], dest: string | string[]): boolean {
if (typeof source === "string" && typeof dest === "string") {
@@ -285,7 +285,7 @@ gulp.task(configureNightlyJs, false, [], () => {
// Nightly management tasks
gulp.task("configure-nightly", "Runs scripts/configureNightly.ts to prepare a build for nightly publishing", [configureNightlyJs], (done) => {
- exec(host, [configureNightlyJs, packageJson, programTs], done, done);
+ exec(host, [configureNightlyJs, packageJson, versionFile], done, done);
});
gulp.task("publish-nightly", "Runs `npm publish --tag next` to create a new nightly build on npm", ["LKG"], () => {
return runSequence("clean", "useDebugMode", "runtests", (done) => {
diff --git a/Jakefile.js b/Jakefile.js
index 2e5d660c4f1d9..646f6e00bcfac 100644
--- a/Jakefile.js
+++ b/Jakefile.js
@@ -593,7 +593,7 @@ task("generate-diagnostics", [diagnosticInfoMapTs]);
var configureNightlyJs = path.join(scriptsDirectory, "configureNightly.js");
var configureNightlyTs = path.join(scriptsDirectory, "configureNightly.ts");
var packageJson = "package.json";
-var programTs = path.join(compilerDirectory, "program.ts");
+var versionFile = path.join(compilerDirectory, "core.ts");
file(configureNightlyTs);
@@ -609,7 +609,7 @@ task("setDebugMode", function () {
});
task("configure-nightly", [configureNightlyJs], function () {
- var cmd = host + " " + configureNightlyJs + " " + packageJson + " " + programTs;
+ var cmd = host + " " + configureNightlyJs + " " + packageJson + " " + versionFile;
console.log(cmd);
exec(cmd);
}, { async: true });
diff --git a/src/compiler/core.ts b/src/compiler/core.ts
index f647480979b3f..92feb5414acdb 100644
--- a/src/compiler/core.ts
+++ b/src/compiler/core.ts
@@ -1,6 +1,11 @@
///
///
+namespace ts {
+ /** The version of the TypeScript compiler release */
+ export const version = "2.2.0";
+}
+
/* @internal */
namespace ts {
/**
diff --git a/src/compiler/program.ts b/src/compiler/program.ts
index 85c27a6383977..041923a885766 100644
--- a/src/compiler/program.ts
+++ b/src/compiler/program.ts
@@ -3,10 +3,6 @@
///
namespace ts {
- /** The version of the TypeScript compiler release */
-
- export const version = "2.2.0";
-
const emptyArray: any[] = [];
export function findConfigFile(searchPath: string, fileExists: (fileName: string) => boolean, configName = "tsconfig.json"): string {
diff --git a/src/server/protocol.ts b/src/server/protocol.ts
index 0d9a0a76d7aa2..dad66f3cc7175 100644
--- a/src/server/protocol.ts
+++ b/src/server/protocol.ts
@@ -2106,6 +2106,11 @@ namespace ts.server.protocol {
* true if install request succeeded, otherwise - false
*/
installSuccess: boolean;
+
+ /**
+ * version of typings installer
+ */
+ typingsInstallerVersion: string;
}
export interface NavBarResponse extends Response {
diff --git a/src/server/server.ts b/src/server/server.ts
index c561277c7d2e5..220b0d90c65e6 100644
--- a/src/server/server.ts
+++ b/src/server/server.ts
@@ -300,7 +300,8 @@ namespace ts.server {
telemetryEventName: "typingsInstalled",
payload: {
installedPackages: response.packagesToInstall.join(","),
- installSuccess: response.installSuccess
+ installSuccess: response.installSuccess,
+ typingsInstallerVersion: response.typingsInstallerVersion
}
};
const eventName: protocol.TelemetryEventName = "telemetry";
diff --git a/src/server/types.d.ts b/src/server/types.d.ts
index 3fd90e7fd3ec8..a4032bf062e8c 100644
--- a/src/server/types.d.ts
+++ b/src/server/types.d.ts
@@ -69,6 +69,7 @@ declare namespace ts.server {
readonly packagesToInstall: ReadonlyArray;
readonly kind: EventInstall;
readonly installSuccess: boolean;
+ readonly typingsInstallerVersion: string;
}
export interface InstallTypingHost extends JsTyping.TypingResolutionHost {
diff --git a/src/server/typingsInstaller/nodeTypingsInstaller.ts b/src/server/typingsInstaller/nodeTypingsInstaller.ts
index 74311dae4e265..bdfdda3033cb8 100644
--- a/src/server/typingsInstaller/nodeTypingsInstaller.ts
+++ b/src/server/typingsInstaller/nodeTypingsInstaller.ts
@@ -61,17 +61,12 @@ namespace ts.server.typingsInstaller {
return combinePaths(normalizeSlashes(globalTypingsCacheLocation), `node_modules/${TypesRegistryPackageName}/index.json`);
}
-
- type Exec = {
- (command: string, options: { cwd: string }, callback?: (error: Error, stdout: string, stderr: string) => void): any
- };
-
type ExecSync = {
- (command: string, options: { cwd: string, stdio: "ignore" }): any
- };
+ (command: string, options: { cwd: string, stdio?: "ignore" }): any
+ }
export class NodeTypingsInstaller extends TypingsInstaller {
- private readonly exec: Exec;
+ private readonly execSync: ExecSync;
private readonly npmPath: string;
readonly typesRegistry: Map;
@@ -87,8 +82,7 @@ namespace ts.server.typingsInstaller {
this.log.writeLine(`Process id: ${process.pid}`);
}
this.npmPath = getNPMLocation(process.argv[0]);
- let execSync: ExecSync;
- ({ exec: this.exec, execSync } = require("child_process"));
+ ({ execSync: this.execSync } = require("child_process"));
this.ensurePackageDirectoryExists(globalTypingsCacheLocation);
@@ -96,7 +90,7 @@ namespace ts.server.typingsInstaller {
if (this.log.isEnabled()) {
this.log.writeLine(`Updating ${TypesRegistryPackageName} npm package...`);
}
- execSync(`${this.npmPath} install ${TypesRegistryPackageName}`, { cwd: globalTypingsCacheLocation, stdio: "ignore" });
+ this.execSync(`${this.npmPath} install ${TypesRegistryPackageName}`, { cwd: globalTypingsCacheLocation, stdio: "ignore" });
}
catch (e) {
if (this.log.isEnabled()) {
@@ -135,13 +129,21 @@ namespace ts.server.typingsInstaller {
}
const command = `${this.npmPath} install ${args.join(" ")} --save-dev`;
const start = Date.now();
- this.exec(command, { cwd }, (err, stdout, stderr) => {
- if (this.log.isEnabled()) {
- this.log.writeLine(`npm install #${requestId} took: ${Date.now() - start} ms${sys.newLine}stdout: ${stdout}${sys.newLine}stderr: ${stderr}`);
- }
- // treat absence of error as success
- onRequestCompleted(!err);
- });
+ let stdout: Buffer;
+ let stderr: Buffer;
+ let hasError = false;
+ try {
+ stdout = this.execSync(command, { cwd });
+ }
+ catch (e) {
+ stdout = e.stdout;
+ stderr = e.stderr;
+ hasError = true;
+ }
+ if (this.log.isEnabled()) {
+ this.log.writeLine(`npm install #${requestId} took: ${Date.now() - start} ms${sys.newLine}stdout: ${stdout && stdout.toString()}${sys.newLine}stderr: ${stderr && stderr.toString()}`);
+ }
+ onRequestCompleted(!hasError);
}
}
diff --git a/src/server/typingsInstaller/typingsInstaller.ts b/src/server/typingsInstaller/typingsInstaller.ts
index 2ea0296e22a75..677e2c7bba098 100644
--- a/src/server/typingsInstaller/typingsInstaller.ts
+++ b/src/server/typingsInstaller/typingsInstaller.ts
@@ -19,9 +19,17 @@ namespace ts.server.typingsInstaller {
writeLine: noop
};
- function typingToFileName(cachePath: string, packageName: string, installTypingHost: InstallTypingHost): string {
- const result = resolveModuleName(packageName, combinePaths(cachePath, "index.d.ts"), { moduleResolution: ModuleResolutionKind.NodeJs }, installTypingHost);
- return result.resolvedModule && result.resolvedModule.resolvedFileName;
+ function typingToFileName(cachePath: string, packageName: string, installTypingHost: InstallTypingHost, log: Log): string {
+ try {
+ const result = resolveModuleName(packageName, combinePaths(cachePath, "index.d.ts"), { moduleResolution: ModuleResolutionKind.NodeJs }, installTypingHost);
+ return result.resolvedModule && result.resolvedModule.resolvedFileName;
+ }
+ catch (e) {
+ if (log.isEnabled()) {
+ log.writeLine(`Failed to resolve ${packageName} in folder '${cachePath}': ${(e).message}`);
+ }
+ return undefined;
+ }
}
export enum PackageNameValidationResult {
@@ -192,8 +200,9 @@ namespace ts.server.typingsInstaller {
if (!packageName) {
continue;
}
- const typingFile = typingToFileName(cacheLocation, packageName, this.installTypingHost);
+ const typingFile = typingToFileName(cacheLocation, packageName, this.installTypingHost, this.log);
if (!typingFile) {
+ this.missingTypingsSet[packageName] = true;
continue;
}
const existingTypingFile = this.packageNameToTypingLocation[packageName];
@@ -224,7 +233,7 @@ namespace ts.server.typingsInstaller {
}
const result: string[] = [];
for (const typing of typingsToInstall) {
- if (this.missingTypingsSet[typing]) {
+ if (this.missingTypingsSet[typing] || this.packageNameToTypingLocation[typing]) {
continue;
}
const validationResult = validatePackageName(typing);
@@ -305,7 +314,8 @@ namespace ts.server.typingsInstaller {
this.sendResponse({
kind: EventInstall,
packagesToInstall: scopedTypings,
- installSuccess: ok
+ installSuccess: ok,
+ typingsInstallerVersion: ts.version // qualified explicitly to prevent occasional shadowing
});
}
@@ -321,16 +331,13 @@ namespace ts.server.typingsInstaller {
// TODO: watch project directory
if (this.log.isEnabled()) {
- this.log.writeLine(`Requested to install typings ${JSON.stringify(scopedTypings)}, installed typings ${JSON.stringify(scopedTypings)}`);
+ this.log.writeLine(`Installed typings ${JSON.stringify(scopedTypings)}`);
}
const installedTypingFiles: string[] = [];
- for (const t of scopedTypings) {
- const packageName = getBaseFileName(t);
- if (!packageName) {
- continue;
- }
- const typingFile = typingToFileName(cachePath, packageName, this.installTypingHost);
+ for (const packageName of filteredTypings) {
+ const typingFile = typingToFileName(cachePath, packageName, this.installTypingHost, this.log);
if (!typingFile) {
+ this.missingTypingsSet[packageName] = true;
continue;
}
if (!this.packageNameToTypingLocation[packageName]) {