nativescript
Version:
Command-line interface for building NativeScript projects
264 lines • 13.3 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;
};
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