UNPKG

symfony-style-console

Version:

Use the style and utilities of the Symfony Console in Node.js

246 lines (245 loc) 8.06 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var OutputFormatterStyle_1 = require("./OutputFormatterStyle"); var OutputFormatterStyleStack_1 = require("./OutputFormatterStyleStack"); var Helper_1 = require("../Helper/Helper"); /** * Formatter class for console output. * * * @author Konstantin Kudryashov <ever.zet@gmail.com> * * Original PHP class * * @author Florian Reuschel <florian@loilo.de> * * Port to TypeScript */ var OutputFormatter = /** @class */ (function () { /** * Initializes console output formatter. * * @param decorated Whether this formatter should actually decorate strings * @param styles Object mappping names to [[OutputFormatterStyleInterface]] instances */ function OutputFormatter(decorated, styles) { if (decorated === void 0) { decorated = false; } if (styles === void 0) { styles = {}; } /** * A mapping of formatter style names to their respective classes. */ this.styles = {}; this.decorated = !!decorated; this.setStyle('error', new OutputFormatterStyle_1.default('white', 'red')); this.setStyle('info', new OutputFormatterStyle_1.default('green')); this.setStyle('comment', new OutputFormatterStyle_1.default('yellow')); this.setStyle('question', new OutputFormatterStyle_1.default('black', 'cyan')); for (var name_1 in styles) { this.setStyle(name_1, styles[name_1]); } this.styleStack = new OutputFormatterStyleStack_1.default(); } /** * Escapes the "<" special char in given text. * * @param text Text to escape * @return Escaped text */ OutputFormatter.escape = function (text) { text = text.replace(/([^\\]?)</g, '$1\\<'); return OutputFormatter.escapeTrailingBackslash(text); }; /** * Escapes trailing backslash "\" in given text. * * @param text Text to escape * @return Escaped text * * @internal */ OutputFormatter.escapeTrailingBackslash = function (text) { if ('\\' === text.slice(-1)) { var len = text.length; text = Helper_1.trimEnd(text, '\\'); text += '<<'.repeat(len - text.length); } return text; }; /** * Creates a new instance containing the same `decorated` flag and styles. * * @return The cloned [[OutputFormatter]] instance */ OutputFormatter.prototype.clone = function () { return new OutputFormatter(this.isDecorated(), Object.assign({}, this.styles)); }; /** * Sets the `decorated` flag property. * * @param decorated Whether to decorate the messages or not */ OutputFormatter.prototype.setDecorated = function (decorated) { this.decorated = !!decorated; }; /** * Gets the `decorated` flag property. * * @return True if the output will decorate messages, false otherwise */ OutputFormatter.prototype.isDecorated = function () { return this.decorated; }; /** * Sets a new style. * * @param name The style name * @param style The style instance */ OutputFormatter.prototype.setStyle = function (name, style) { this.styles[name.toLowerCase()] = style; }; /** * Checks if output formatter has style with specified name. * * @param string name * @return bool */ OutputFormatter.prototype.hasStyle = function (name) { return !!this.styles[name.toLowerCase()]; }; /** * Gets style options from style with specified name. * * @param name * @return The style * * @throws ReferenceError When style isn't defined */ OutputFormatter.prototype.getStyle = function (name) { if (!this.hasStyle(name)) { throw new ReferenceError("Undefined style: " + name); } return this.styles[name.toLowerCase()]; }; /** * Formats a message according to the given styles. * * @param message The message to style * * @return The styled message */ OutputFormatter.prototype.format = function (message) { message = String(message); var offset = 0; var output = ''; var tagRegex = '[a-z][a-z0-9,_=;-]*'; var tagsRegex = new RegExp("<((" + tagRegex + ")|\\/(" + tagRegex + ")?)>", 'gi'); var match; while ((match = tagsRegex.exec(message))) { var text = match[0]; var pos = match.index; if (0 != pos && '\\' == message[pos - 1]) { continue; } // add the text up to the next tag output += this.applyCurrentStyle(message.substr(offset, pos - offset)); offset = pos + text.length; // opening tag? var open_1 = '/' !== text[1]; var tag = void 0; if (open_1) { tag = match[1]; } else { tag = match[3] || ''; } var style = this.createStyleFromString(tag.toLowerCase()); if (!open_1 && !tag) { // </> this.styleStack.pop(); } else if (false === style) { output += this.applyCurrentStyle(text); } else if (open_1) { this.styleStack.push(style); } else { this.styleStack.pop(style); } } output += this.applyCurrentStyle(message.slice(offset)); if (-1 !== output.indexOf('<<')) { return Helper_1.safeReplace(output, { '\\<': '<', '<<': '\\' }); } return output.replace(/\\</g, '<'); }; /** * Gets the used style stack. */ OutputFormatter.prototype.getStyleStack = function () { return this.styleStack; }; /** * Tries to create new [[OutputFormatterStyleInterface]] instance from string. * * @param str The string to create the formatter style from * @return `false` if `str` is not format string */ OutputFormatter.prototype.createStyleFromString = function (str) { if (this.styles[str]) { return this.styles[str]; } var styleRegex = /([^=]+)=([^;]+)(;|$)/g; var style = new OutputFormatterStyle_1.default(); var gotMatch = false; var match; while ((match = styleRegex.exec(str))) { gotMatch = true; if ('fg' == match[1]) { style.setForeground(match[2]); } else if ('bg' == match[1]) { style.setBackground(match[2]); } else if ('options' === match[1]) { var options = Array.from(match[2].match(/([^,;]+)/g)); for (var _i = 0, options_1 = options; _i < options_1.length; _i++) { var option = options_1[_i]; try { style.setOption(option); } catch (e) { console.warn("Unknown style options are deprecated since version 3.2 and will be removed in 4.0. Error \"" + e + "\"."); return false; } } } else { return false; } } if (gotMatch) { return style; } else { return false; } }; /** * Applies current style from stack to text, if must be applied. * * @param text The text to format * @return The formatted text */ OutputFormatter.prototype.applyCurrentStyle = function (text) { return this.isDecorated() && text.length > 0 ? this.styleStack.getCurrent().apply(text) : text; }; return OutputFormatter; }()); exports.default = OutputFormatter;