UNPKG

mobile-cli-lib

Version:
272 lines (271 loc) 15.2 kB
"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);