UNPKG

nativescript

Version:

Command-line interface for building NativeScript projects

264 lines • 13.3 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; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.AutoCompletionService = void 0; const os_1 = require("os"); const path = require("path"); const util = require("util"); const _ = require("lodash"); const decorators_1 = require("../decorators"); const yok_1 = require("../yok"); class AutoCompletionService { constructor($fs, $childProcess, $logger, $staticConfig, $hostInfo) { this.$fs = $fs; this.$childProcess = $childProcess; this.$logger = $logger; this.$staticConfig = $staticConfig; this.$hostInfo = $hostInfo; this.scriptsOk = true; this.scriptsUpdated = false; this.disableAnalytics = true; } get shellProfiles() { return [ this.getHomePath(".bashrc"), this.getHomePath(".zshrc"), // zsh - http://www.acm.uiuc.edu/workshops/zsh/startup_files.html ]; } get cliRunCommandsFile() { let cliRunCommandsFile = this.getHomePath(util.format(".%src", this.$staticConfig.CLIENT_NAME.toLowerCase())); if (this.$hostInfo.isWindows) { // on Windows bash, file is incorrectly written as C:\Users\<username>, which leads to errors when trying to execute the script: // $ source ~/.bashrc // sh.exe": C:Usersusername.appbuilderrc: No such file or directory cliRunCommandsFile = cliRunCommandsFile.replace(/\\/g, "/"); } return cliRunCommandsFile; } getTabTabObsoleteRegex(clientName) { const tabTabStartPoint = util.format(AutoCompletionService.TABTAB_COMPLETION_START_REGEX_PATTERN, clientName.toLowerCase()); const tabTabEndPoint = util.format(AutoCompletionService.TABTAB_COMPLETION_END_REGEX_PATTERN, clientName.toLowerCase()); const tabTabRegex = new RegExp(util.format("%s[\\s\\S]*%s", tabTabStartPoint, tabTabEndPoint)); return tabTabRegex; } getTabTabCompletionsRegex() { return new RegExp(util.format("%s[\\s\\S]*%s", AutoCompletionService.GENERATED_TABTAB_COMPLETION_START, AutoCompletionService.GENERATED_TABTAB_COMPLETION_END)); } removeObsoleteAutoCompletion() { // In previous releases we were writing directly in .bash_profile, .bashrc, .zshrc and .profile - remove this old code const shellProfilesToBeCleared = this.shellProfiles; // Add .profile only here as we do not want new autocompletion in this file, but we have to remove our old code from it. shellProfilesToBeCleared.push(this.getHomePath(".profile")); shellProfilesToBeCleared.forEach((file) => { try { const text = this.$fs.readText(file); let newText = text.replace(this.getTabTabObsoleteRegex(this.$staticConfig.CLIENT_NAME), ""); if (this.$staticConfig.CLIENT_NAME_ALIAS) { newText = newText.replace(this.getTabTabObsoleteRegex(this.$staticConfig.CLIENT_NAME_ALIAS), ""); } if (newText !== text) { this.$logger.trace("Remove obsolete AutoCompletion from file %s.", file); this.$fs.writeFile(file, newText); } } catch (error) { if (error.code !== "ENOENT") { this.$logger.trace("Error while trying to disable autocompletion for '%s' file. Error is:\n%s", error.toString()); } } }); } removeOboleteTabTabCompletion(text) { try { let newText = text.replace(this.getTabTabObsoleteRegex("ns"), ""); newText = newText.replace(this.getTabTabObsoleteRegex("nsc"), ""); newText = newText.replace(this.getTabTabObsoleteRegex("nativescript"), ""); newText = newText.replace(this.getTabTabObsoleteRegex("tns"), ""); return newText; } catch (error) { this.$logger.trace("Error while trying to disable autocompletion for '%s' file. Error is:\n%s", error.toString()); return text; } } get completionAliasDefinition() { const pattern = "compdef _nativescript.js_yargs_completions %s"; const ns = util.format(pattern, "ns"); const tns = util.format(pattern, "tns"); return util.format("\n%s\n%s\n%s\n", ns, tns, AutoCompletionService.GENERATED_TABTAB_COMPLETION_END); } get completionShellScriptContent() { const startText = util.format(AutoCompletionService.COMPLETION_START_COMMENT_PATTERN, this.$staticConfig.CLIENT_NAME.toLowerCase()); const content = util.format("if [ -f %s ]; then \n source %s \nfi", this.cliRunCommandsFile, this.cliRunCommandsFile); const endText = util.format(AutoCompletionService.COMPLETION_END_COMMENT_PATTERN, this.$staticConfig.CLIENT_NAME.toLowerCase()); return util.format("\n%s\n%s\n%s\n", startText, content, endText); } isAutoCompletionEnabled() { let result = true; _.each(this.shellProfiles, (filePath) => { result = this.isNewAutoCompletionEnabledInFile(filePath) || this.isObsoleteAutoCompletionEnabledInFile(filePath); if (!result) { // break each return false; } }); return result; } disableAutoCompletion() { _.each(this.shellProfiles, (shellFile) => this.removeAutoCompletionFromShellScript(shellFile)); this.removeObsoleteAutoCompletion(); if (this.scriptsOk && this.scriptsUpdated) { this.$logger.info("Restart your shell to disable command auto-completion."); } } async enableAutoCompletion() { await this.updateCLIShellScript(); _.each(this.shellProfiles, (shellFile) => this.addAutoCompletionToShellScript(shellFile)); this.removeObsoleteAutoCompletion(); if (this.scriptsOk && this.scriptsUpdated) { this.$logger.info("Restart your shell to enable command auto-completion."); } } isObsoleteAutoCompletionEnabled() { let result = true; _.each(this.shellProfiles, (shellProfile) => { result = this.isObsoleteAutoCompletionEnabledInFile(shellProfile); if (!result) { // break each return false; } }); return result; } isNewAutoCompletionEnabledInFile(fileName) { try { const data = this.$fs.readText(fileName); if (data && data.indexOf(this.completionShellScriptContent) !== -1) { return true; } } catch (err) { this.$logger.trace("Error while checking is autocompletion enabled in file %s. Error is: '%s'", fileName, err.toString()); } return false; } isObsoleteAutoCompletionEnabledInFile(fileName) { try { const text = this.$fs.readText(fileName); return !!(text.match(this.getTabTabObsoleteRegex(this.$staticConfig.CLIENT_NAME)) || text.match(this.getTabTabObsoleteRegex(this.$staticConfig.CLIENT_NAME))); } catch (err) { this.$logger.trace("Error while checking is obsolete autocompletion enabled in file %s. Error is: '%s'", fileName, err.toString()); } } addAutoCompletionToShellScript(fileName) { try { if (!this.isNewAutoCompletionEnabledInFile(fileName) || this.isObsoleteAutoCompletionEnabledInFile(fileName)) { this.$logger.trace("AutoCompletion is not enabled in %s file. Trying to enable it.", fileName); this.$fs.appendFile(fileName, this.completionShellScriptContent); this.scriptsUpdated = true; } } catch (err) { this.$logger.info("Unable to update %s. Command-line completion might not work.", fileName); // When npm is installed with sudo, in some cases the installation cannot write to shell profiles // Advise the user how to enable autocompletion after the installation is completed. if ((err.code === "EPERM" || err.code === "EACCES") && !this.$hostInfo.isWindows && process.env.SUDO_USER) { this.$logger.info("To enable command-line completion, run '$ %s autocomplete enable'.", this.$staticConfig.CLIENT_NAME); } this.$logger.trace(err); this.scriptsOk = false; } } removeAutoCompletionFromShellScript(fileName) { try { if (this.isNewAutoCompletionEnabledInFile(fileName)) { this.$logger.trace("AutoCompletion is enabled in %s file. Trying to disable it.", fileName); let data = this.$fs.readText(fileName); data = data.replace(this.completionShellScriptContent, ""); this.$fs.writeFile(fileName, data); this.scriptsUpdated = true; } } catch (err) { // If file does not exist, autocompletion was not working for it, so ignore this error. if (err.code !== "ENOENT") { this.$logger.info("Failed to update %s. Auto-completion may still work or work incorrectly. ", fileName); this.$logger.info(err); this.scriptsOk = false; } } } async updateCLIShellScript() { const filePath = this.cliRunCommandsFile; try { let doUpdate = true; if (this.$fs.exists(filePath)) { const contents = this.$fs.readText(filePath); const regExp = new RegExp(AutoCompletionService.GENERATED_TABTAB_COMPLETION_START); let matchCondition = contents.match(regExp); if (matchCondition) { doUpdate = false; } } if (doUpdate) { const clientExecutableFileName = (this.$staticConfig.CLIENT_NAME_ALIAS || this.$staticConfig.CLIENT_NAME).toLowerCase(); const pathToExecutableFile = path.join(__dirname, `../../../bin/${clientExecutableFileName}.js`); if (this.$fs.exists(filePath)) { const existingText = this.$fs.readText(filePath); let newText = existingText.replace(this.getTabTabCompletionsRegex(), ""); newText = this.removeOboleteTabTabCompletion(newText); if (newText !== existingText) { this.$logger.trace("Remove existing AutoCompletion from file %s.", filePath); this.$fs.writeFile(filePath, newText); } } // The generated seems to be inconsistent in it's start/end markers so adding our own. this.$fs.appendFile(filePath, `\n${AutoCompletionService.GENERATED_TABTAB_COMPLETION_START}\n`); await this.$childProcess.exec(`"${process.argv[0]}" "${pathToExecutableFile}" completion_generate_script >> "${filePath}"`); this.$fs.appendFile(filePath, this.completionAliasDefinition); this.$fs.chmod(filePath, "0644"); } } catch (err) { this.$logger.info("Failed to update %s. Auto-completion may not work. ", filePath); this.$logger.trace(err); this.scriptsOk = false; } } getHomePath(fileName) { return path.join((0, os_1.homedir)(), fileName); } } exports.AutoCompletionService = AutoCompletionService; AutoCompletionService.COMPLETION_START_COMMENT_PATTERN = "###-%s-completion-start-###"; AutoCompletionService.COMPLETION_END_COMMENT_PATTERN = "###-%s-completion-end-###"; AutoCompletionService.TABTAB_COMPLETION_START_REGEX_PATTERN = "###-begin-%s-completion-###"; AutoCompletionService.TABTAB_COMPLETION_END_REGEX_PATTERN = "###-end-%s-completion-###"; AutoCompletionService.GENERATED_TABTAB_COMPLETION_END = "###-end-ns-completions-section-###"; AutoCompletionService.GENERATED_TABTAB_COMPLETION_START = "###-begin-ns-completions-section-###"; __decorate([ (0, decorators_1.cache)() ], AutoCompletionService.prototype, "shellProfiles", null); __decorate([ (0, decorators_1.cache)() ], AutoCompletionService.prototype, "cliRunCommandsFile", null); __decorate([ (0, decorators_1.cache)() ], AutoCompletionService.prototype, "completionAliasDefinition", null); __decorate([ (0, decorators_1.cache)() ], AutoCompletionService.prototype, "completionShellScriptContent", null); yok_1.injector.register("autoCompletionService", AutoCompletionService); //# sourceMappingURL=auto-completion-service.js.map