mobile-cli-lib
Version:
common lib used by different CLI
272 lines (271 loc) • 15.2 kB
JavaScript
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var path = require("path");
var os = require("os");
var temp = require("temp");
var decorators_1 = require("../decorators");
var constants_1 = require("../constants");
temp.track();
var TypeScriptService = (function () {
function TypeScriptService($childProcess, $fs, $logger, $npmService, $options, $projectConstants, $processService, $errors) {
this.$childProcess = $childProcess;
this.$fs = $fs;
this.$logger = $logger;
this.$npmService = $npmService;
this.$options = $options;
this.$projectConstants = $projectConstants;
this.$processService = $processService;
this.$errors = $errors;
}
TypeScriptService.prototype.transpile = function (projectDir, typeScriptFiles, definitionFiles, options) {
var _this = this;
return (function () {
options = options || {};
var compilerOptions = _this.getCompilerOptions(projectDir, options).wait();
var typeScriptCompilerSettings = _this.getTypeScriptCompilerSettings({ useLocalTypeScriptCompiler: options.useLocalTypeScriptCompiler }).wait();
_this.noEmitOnError = compilerOptions.noEmitOnError;
_this.typeScriptFiles = typeScriptFiles || [];
_this.definitionFiles = definitionFiles || [];
var runTranspilationOptions = { compilerOptions: compilerOptions };
if (_this.typeScriptFiles.length > 0) {
var typeScriptDefinitionsFiles = [];
if (!_this.hasTsConfigFile(projectDir).wait()) {
typeScriptDefinitionsFiles = _this.getDefaultTypeScriptDefinitionsFiles(options.pathToDefaultDefinitionFiles).wait();
}
typeScriptDefinitionsFiles = typeScriptDefinitionsFiles.concat(_this.getTypeScriptFilesData(projectDir).wait().definitionFiles);
var filesToTranspile = _this.typeScriptFiles.concat(typeScriptDefinitionsFiles);
_this.$logger.out("Compiling...".yellow);
_.each(_this.typeScriptFiles, function (file) {
_this.$logger.out(("### Compile " + file).cyan);
});
runTranspilationOptions.filesToTranspile = filesToTranspile;
}
_this.$logger.out(("Using tsc version " + typeScriptCompilerSettings.version).cyan);
return _this.runTranspilation(projectDir, typeScriptCompilerSettings.pathToCompiler, runTranspilationOptions).wait();
}).future()();
};
TypeScriptService.prototype.getTypeScriptFilesData = function (projectDir) {
var _this = this;
return (function () {
var rootNodeModules = path.join(projectDir, constants_1.NODE_MODULES_DIR_NAME);
var projectFiles = _this.$fs.enumerateFilesInDirectorySync(projectDir, function (fileName, fstat) { return fileName !== rootNodeModules; });
var typeScriptFiles = _.filter(projectFiles, _this.isTypeScriptFile);
var definitionFiles = _.filter(typeScriptFiles, function (file) { return _.endsWith(file, constants_1.FileExtensions.TYPESCRIPT_DEFINITION_FILE); });
return { definitionFiles: definitionFiles, typeScriptFiles: _.difference(typeScriptFiles, definitionFiles) };
}).future()();
};
TypeScriptService.prototype.isTypeScriptProject = function (projectDir) {
var _this = this;
return (function () {
var typeScriptFilesData = _this.getTypeScriptFilesData(projectDir).wait();
return !!typeScriptFilesData.typeScriptFiles.length;
}).future()();
};
TypeScriptService.prototype.isTypeScriptFile = function (file) {
return path.extname(file) === constants_1.FileExtensions.TYPESCRIPT_FILE;
};
TypeScriptService.prototype.hasTsConfigFile = function (projectDir) {
return this.$fs.exists(this.getPathToTsConfigFile(projectDir));
};
TypeScriptService.prototype.getPathToTsConfigFile = function (projectDir) {
return path.join(projectDir, this.$projectConstants.TSCONFIG_JSON_NAME);
};
TypeScriptService.prototype.getCompilerOptions = function (projectDir, options) {
var _this = this;
return (function () {
var tsConfigFile;
var pathToConfigJsonFile = _this.getPathToTsConfigFile(projectDir);
if (_this.hasTsConfigFile(projectDir).wait()) {
tsConfigFile = _this.$fs.readJson(pathToConfigJsonFile).wait();
}
tsConfigFile = tsConfigFile || { compilerOptions: {} };
var compilerOptions = options.compilerOptions || {};
var defaultOptions = options.defaultCompilerOptions || {};
var compilerOptionsKeys = _.union(_.keys(compilerOptions), _.keys(tsConfigFile.compilerOptions), _.keys(defaultOptions));
var result = {};
_.each(compilerOptionsKeys, function (key) {
result[key] = _this.getCompilerOptionByKey(key, compilerOptions, tsConfigFile.compilerOptions, defaultOptions);
});
result.noEmitOnError = result.noEmitOnError || false;
return result;
}).future()();
};
TypeScriptService.prototype.getCompilerOptionByKey = function (key, compilerOptions, tsConfigFileOptions, defaultOptions) {
if (_.has(compilerOptions, key)) {
return compilerOptions[key];
}
if (_.has(tsConfigFileOptions, key)) {
return tsConfigFileOptions[key];
}
return defaultOptions[key];
};
TypeScriptService.prototype.getTypeScriptCompilerSettings = function (options) {
var _this = this;
return (function () {
var typeScriptInNodeModulesDir = path.join(constants_1.NODE_MODULES_DIR_NAME, TypeScriptService.TYPESCRIPT_MODULE_NAME);
if (!_this.typeScriptModuleFilePath) {
if (options.useLocalTypeScriptCompiler) {
var typeScriptJsFilePath = require.resolve(TypeScriptService.TYPESCRIPT_MODULE_NAME);
_this.typeScriptModuleFilePath = typeScriptJsFilePath.substring(0, typeScriptJsFilePath.indexOf(typeScriptInNodeModulesDir) + typeScriptInNodeModulesDir.length);
}
else {
var typeScriptModuleInstallationDir = _this.createTempDirectoryForTsc().wait();
var pluginToInstall = {
name: TypeScriptService.TYPESCRIPT_MODULE_NAME,
version: TypeScriptService.DEFAULT_TSC_VERSION,
installTypes: false
};
_this.$npmService.install(typeScriptModuleInstallationDir, pluginToInstall).wait();
_this.typeScriptModuleFilePath = path.join(typeScriptModuleInstallationDir, typeScriptInNodeModulesDir);
}
}
var typeScriptCompilerPath = path.join(_this.typeScriptModuleFilePath, "lib", "tsc");
var typeScriptCompilerVersion = _this.$fs.readJson(path.join(_this.typeScriptModuleFilePath, _this.$projectConstants.PACKAGE_JSON_NAME)).wait().version;
return { pathToCompiler: typeScriptCompilerPath, version: typeScriptCompilerVersion };
}).future()();
};
TypeScriptService.prototype.runTranspilation = function (projectDir, typeScriptCompilerPath, options) {
var _this = this;
return (function () {
options = options || {};
var startTime = new Date().getTime();
var params = _([])
.concat(typeScriptCompilerPath)
.concat(options.filesToTranspile || [])
.concat(_this.getTypeScriptCompilerOptionsAsArguments(options.compilerOptions) || [])
.value();
var output = _this.$childProcess.spawnFromEvent(process.argv[0], params, "close", { cwd: projectDir }, { throwError: false }).wait();
var compilerOutput = output.stderr || output.stdout;
var compilerMessages = _this.getCompilerMessages(compilerOutput);
_this.logCompilerMessages(compilerMessages, compilerOutput);
var endTime = new Date().getTime();
var time = (endTime - startTime) / 1000;
_this.$logger.out((os.EOL + "Success: " + time.toFixed(2) + "s" + os.EOL + ".").green);
_this.startWatchProcess(params, projectDir);
return compilerOutput;
}).future()();
};
TypeScriptService.prototype.startWatchProcess = function (params, projectDir) {
if (!this._watchProcess && this.$options.watch) {
params.push("--watch");
this._watchProcess = this.$childProcess.spawn(process.argv[0], params, { cwd: projectDir });
this.$processService.attachToProcessExitSignals(null, this._watchProcess.kill);
}
};
TypeScriptService.prototype.getCompilerMessages = function (compilerOutput) {
var _this = this;
var level1ErrorCount = 0, level5ErrorCount = 0, nonEmitPreventingWarningCount = 0;
var hasPreventEmitErrors = _.reduce(compilerOutput.split("\n"), function (memo, errorMsg) {
var isPreventEmitError = !!_this.noEmitOnError;
if (errorMsg.search(/error TS1\d+:/) >= 0) {
level1ErrorCount += 1;
}
else if (errorMsg.search(/error TS5\d+:/) >= 0) {
level5ErrorCount += 1;
}
else if (errorMsg.search(/error TS\d+:/) >= 0) {
nonEmitPreventingWarningCount += 1;
}
return memo || isPreventEmitError;
}, false) || false;
return {
level1ErrorCount: level1ErrorCount,
level5ErrorCount: level5ErrorCount,
nonEmitPreventingWarningCount: nonEmitPreventingWarningCount,
hasPreventEmitErrors: hasPreventEmitErrors
};
};
TypeScriptService.prototype.logCompilerMessages = function (compilerMessages, errorMessage) {
var level1ErrorCount = compilerMessages.level1ErrorCount, level5ErrorCount = compilerMessages.level5ErrorCount, nonEmitPreventingWarningCount = compilerMessages.nonEmitPreventingWarningCount, hasPreventEmitErrors = compilerMessages.hasPreventEmitErrors;
if (level1ErrorCount + level5ErrorCount + nonEmitPreventingWarningCount > 0) {
var colorizedMessage = (level1ErrorCount + level5ErrorCount > 0) ? ">>>".red : ">>>".green;
this.$logger.out(colorizedMessage);
var errorTitle = "";
if (level5ErrorCount > 0) {
errorTitle += this.composeErrorTitle(level5ErrorCount, "compiler flag error");
}
if (level1ErrorCount > 0) {
errorTitle += this.composeErrorTitle(level1ErrorCount, "syntax error");
}
if (nonEmitPreventingWarningCount > 0) {
if (!level1ErrorCount && !level5ErrorCount && this.noEmitOnError) {
errorTitle += this.composeErrorTitle(nonEmitPreventingWarningCount, "non-emit-preventing type errors, but output is not generated as noEmitOnError option is true.");
}
else {
errorTitle += this.composeErrorTitle(nonEmitPreventingWarningCount, "non-emit-preventing type warning");
}
}
if (hasPreventEmitErrors) {
this.$errors.failWithoutHelp("" + os.EOL + errorTitle + os.EOL + errorMessage.red + os.EOL + ">>> ".red);
}
else {
this.$logger.out(errorTitle);
this.$logger.warn(errorMessage);
this.$logger.out(">>>".green);
}
}
};
TypeScriptService.prototype.composeErrorTitle = function (count, title) {
return count + " " + title + ((count === 1) ? '' : 's') + " " + os.EOL;
};
TypeScriptService.prototype.getTypeScriptCompilerOptionsAsArguments = function (options) {
this.noEmitOnError = options.noEmitOnError;
return _(options)
.keys()
.map(function (option) {
var value = options[option];
if (typeof (value) === "string") {
return [("--" + option), value];
}
else if (value) {
return [("--" + option)];
}
else {
return null;
}
})
.filter(function (argument) { return !!argument; })
.flatten()
.value();
};
TypeScriptService.prototype.getDefaultTypeScriptDefinitionsFiles = function (defaultTypeScriptDefinitionsFilesPath) {
var _this = this;
return (function () {
if (!_this.$fs.exists(defaultTypeScriptDefinitionsFilesPath).wait()) {
return [];
}
var defaultDefinitionsFiles = _this.$fs.readDirectory(defaultTypeScriptDefinitionsFilesPath).wait();
var remainingDefaultDefinitionFiles = _.filter(defaultDefinitionsFiles, function (defFile) { return !_.some(_this.definitionFiles, function (f) { return path.basename(f) === defFile; }); });
return _.map(remainingDefaultDefinitionFiles, function (definitionFilePath) {
return path.join(defaultTypeScriptDefinitionsFilesPath, definitionFilePath);
}).concat(_this.definitionFiles);
}).future()();
};
TypeScriptService.prototype.createTempDirectoryForTsc = function () {
var _this = this;
return (function () {
var tempDir = temp.mkdirSync("typescript-compiler-" + TypeScriptService.DEFAULT_TSC_VERSION);
_this.$fs.writeJson(path.join(tempDir, _this.$projectConstants.PACKAGE_JSON_NAME), { name: "tsc-container", version: "1.0.0" }).wait();
return tempDir;
}).future()();
};
TypeScriptService.DEFAULT_TSC_VERSION = "1.8.10";
TypeScriptService.TYPESCRIPT_MODULE_NAME = "typescript";
__decorate([
decorators_1.exportedPromise("typeScriptService"),
__metadata('design:type', Function),
__metadata('design:paramtypes', [String, Array, Array, Object]),
__metadata('design:returntype', Object)
], TypeScriptService.prototype, "transpile", null);
return TypeScriptService;
}());
exports.TypeScriptService = TypeScriptService;
$injector.register("typeScriptService", TypeScriptService);