UNPKG

ansi-parser

Version:

Parse strings containing ANSI style characters.

235 lines (209 loc) 5.53 kB
"use strict"; function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } // Constructor var AnsiParser = module.exports = {}; /** * parse * Parses the string containing ANSI styles. * * @name parse * @function * @param {String} input The input string. * @return {Array} An array of object like below: * * * ```js * [ * { * style: "\u00\u001b[1m\u001b[38;5;231", * content: "H" * }, * { * style: "\u00\u001b[1m\u001b[38;5;231", * content: "e" * }, * ... * ] * ``` */ AnsiParser.parse = function (input) { var i = 0; if (Array.isArray(input)) { var arr = []; for (i = 0; i < input.length; ++i) { arr.push(AnsiParser.parse(input[i])); } return arr; } if (typeof input !== "string") { throw new Error("Input is not a string."); } var noAnsi = AnsiParser.removeAnsi(input); if (input === noAnsi) { return input.split("").map(function (c) { return { style: "", content: c }; }); } var result = [], sIndex = 0, cmatch, color = []; i = 0; while (sIndex < input.length) { cmatch = input.substr(sIndex).match(/^(\u001B\[[^m]*m)/); if (cmatch) { if (cmatch[0] == '\x1B[0m') { color = []; } else { if (/^\u001b\[38;5/.test(cmatch[0]) && /^\u001b\[38;5/.test(color.slice(-1)[0])) { color.splice(-1); } color.push(cmatch[0]); } sIndex += cmatch[0].length; } else { result.push({ style: color.join(""), content: noAnsi[i++] }); ++sIndex; } } return result; }; /** * getAtIndex * Returns the content and ANSI style at known index. * * @name getAtIndex * @function * @param {String} input The input string. * @param {String} noAnsi The input string without containing ansi styles. * @param {Number} index The character index. * @return {Object} An object containing the following fields: * * - `style` (String): The ANSI style at provided index. * - `content` (String): The content (character) at provided index. */ AnsiParser.getAtIndex = function (input, noAnsi, index) { if (typeof noAnsi === "number") { index = noAnsi; noAnsi = AnsiParser.removeAnsi(input); } if (input === noAnsi) { return { style: "", content: noAnsi[index] }; } var sIndex = 0, eIndex = index, color = [], cmatch; while (sIndex < input.length) { cmatch = input.substr(sIndex).match(/^(\u001B\[[^m]*m)/); if (cmatch) { if (cmatch[0] == '\x1B[0m') { color = []; } else { if (/^\u001b\[38;5/.test(cmatch[0]) && /^\u001b\[38;5/.test(color.slice(-1)[0])) { color.splice(-1); } color.push(cmatch[0]); } sIndex += cmatch[0].length; } else { if (!eIndex) { break; } ++sIndex; --eIndex; } } return { style: color.join(""), content: noAnsi[index] }; }; /** * removeAnsi * Removes ANSI styles from the input string. * * @name removeAnsi * @function * @param {String} input The input string. * @return {String} The string without ANSI styles. */ AnsiParser.removeAnsi = function (input) { return input.replace(/\u001b\[.*?m/g, ""); }; /** * stringify * Stringifies an array of objects in the format defined by `AnsiParser`. * * @name stringify * @function * @param {Array} arr The input array. * @return {String} The stringified input array. */ AnsiParser.stringify = function (arr) { var str = "", cArr = null, i = 0; if (arr && Array.isArray(arr[0])) { for (; i < arr.length; ++i) { str += AnsiParser.stringify(arr[i]) + "\n"; } str = str.replace(/\n$/, ""); return str; } var lastStyle = "", cStyle = "", uStyle = ""; for (; i < arr.length; ++i) { cArr = arr[i]; if (cArr === undefined) { cArr = arr[i] = { style: "", content: " " }; } cStyle = cArr.style; if (cStyle === lastStyle) { uStyle = ""; } else { if (cStyle === "") { uStyle = "\x1B[0m"; lastStyle = ""; } else { uStyle = cStyle; lastStyle = cStyle; } } str += uStyle + cArr.content; if (cArr.content === "\n") { str += "\x1B[0m"; } } if (!/\u001b\[0m$/.test(str)) { str += "\x1B[0m"; } return str; }; /** * addChar * Adds a new char into array. * * @name addChar * @function * @param {Array} arr The input array. * @param {String} c The char to add. * @param {String} s ANSI start style. * @param {String} e ANSI end style. */ AnsiParser.addChar = function (arr, c, s, e) { arr.push(_defineProperty({ start: s || "", content: c }, "start", e || "")); };