1 |
3a515b92
|
cagy
|
'use strict'
|
2 |
|
|
|
3 |
|
|
module.exports = ansiHTML
|
4 |
|
|
|
5 |
|
|
// Reference to https://github.com/sindresorhus/ansi-regex
|
6 |
|
|
var _regANSI = /(?:(?:\u001b\[)|\u009b)(?:(?:[0-9]{1,3})?(?:(?:;[0-9]{0,3})*)?[A-M|f-m])|\u001b[A-M]/
|
7 |
|
|
|
8 |
|
|
var _defColors = {
|
9 |
|
|
reset: ['fff', '000'], // [FOREGROUD_COLOR, BACKGROUND_COLOR]
|
10 |
|
|
black: '000',
|
11 |
|
|
red: 'ff0000',
|
12 |
|
|
green: '209805',
|
13 |
|
|
yellow: 'e8bf03',
|
14 |
|
|
blue: '0000ff',
|
15 |
|
|
magenta: 'ff00ff',
|
16 |
|
|
cyan: '00ffee',
|
17 |
|
|
lightgrey: 'f0f0f0',
|
18 |
|
|
darkgrey: '888'
|
19 |
|
|
}
|
20 |
|
|
var _styles = {
|
21 |
|
|
30: 'black',
|
22 |
|
|
31: 'red',
|
23 |
|
|
32: 'green',
|
24 |
|
|
33: 'yellow',
|
25 |
|
|
34: 'blue',
|
26 |
|
|
35: 'magenta',
|
27 |
|
|
36: 'cyan',
|
28 |
|
|
37: 'lightgrey'
|
29 |
|
|
}
|
30 |
|
|
var _openTags = {
|
31 |
|
|
'1': 'font-weight:bold', // bold
|
32 |
|
|
'2': 'opacity:0.5', // dim
|
33 |
|
|
'3': '<i>', // italic
|
34 |
|
|
'4': '<u>', // underscore
|
35 |
|
|
'8': 'display:none', // hidden
|
36 |
|
|
'9': '<del>' // delete
|
37 |
|
|
}
|
38 |
|
|
var _closeTags = {
|
39 |
|
|
'23': '</i>', // reset italic
|
40 |
|
|
'24': '</u>', // reset underscore
|
41 |
|
|
'29': '</del>' // reset delete
|
42 |
|
|
}
|
43 |
|
|
|
44 |
|
|
;[0, 21, 22, 27, 28, 39, 49].forEach(function (n) {
|
45 |
|
|
_closeTags[n] = '</span>'
|
46 |
|
|
})
|
47 |
|
|
|
48 |
|
|
/**
|
49 |
|
|
* Converts text with ANSI color codes to HTML markup.
|
50 |
|
|
* @param {String} text
|
51 |
|
|
* @returns {*}
|
52 |
|
|
*/
|
53 |
|
|
function ansiHTML (text) {
|
54 |
|
|
// Returns the text if the string has no ANSI escape code.
|
55 |
|
|
if (!_regANSI.test(text)) {
|
56 |
|
|
return text
|
57 |
|
|
}
|
58 |
|
|
|
59 |
|
|
// Cache opened sequence.
|
60 |
|
|
var ansiCodes = []
|
61 |
|
|
// Replace with markup.
|
62 |
|
|
var ret = text.replace(/\033\[(\d+)*m/g, function (match, seq) {
|
63 |
|
|
var ot = _openTags[seq]
|
64 |
|
|
if (ot) {
|
65 |
|
|
// If current sequence has been opened, close it.
|
66 |
|
|
if (!!~ansiCodes.indexOf(seq)) { // eslint-disable-line no-extra-boolean-cast
|
67 |
|
|
ansiCodes.pop()
|
68 |
|
|
return '</span>'
|
69 |
|
|
}
|
70 |
|
|
// Open tag.
|
71 |
|
|
ansiCodes.push(seq)
|
72 |
|
|
return ot[0] === '<' ? ot : '<span style="' + ot + ';">'
|
73 |
|
|
}
|
74 |
|
|
|
75 |
|
|
var ct = _closeTags[seq]
|
76 |
|
|
if (ct) {
|
77 |
|
|
// Pop sequence
|
78 |
|
|
ansiCodes.pop()
|
79 |
|
|
return ct
|
80 |
|
|
}
|
81 |
|
|
return ''
|
82 |
|
|
})
|
83 |
|
|
|
84 |
|
|
// Make sure tags are closed.
|
85 |
|
|
var l = ansiCodes.length
|
86 |
|
|
;(l > 0) && (ret += Array(l + 1).join('</span>'))
|
87 |
|
|
|
88 |
|
|
return ret
|
89 |
|
|
}
|
90 |
|
|
|
91 |
|
|
/**
|
92 |
|
|
* Customize colors.
|
93 |
|
|
* @param {Object} colors reference to _defColors
|
94 |
|
|
*/
|
95 |
|
|
ansiHTML.setColors = function (colors) {
|
96 |
|
|
if (typeof colors !== 'object') {
|
97 |
|
|
throw new Error('`colors` parameter must be an Object.')
|
98 |
|
|
}
|
99 |
|
|
|
100 |
|
|
var _finalColors = {}
|
101 |
|
|
for (var key in _defColors) {
|
102 |
|
|
var hex = colors.hasOwnProperty(key) ? colors[key] : null
|
103 |
|
|
if (!hex) {
|
104 |
|
|
_finalColors[key] = _defColors[key]
|
105 |
|
|
continue
|
106 |
|
|
}
|
107 |
|
|
if ('reset' === key) {
|
108 |
|
|
if (typeof hex === 'string') {
|
109 |
|
|
hex = [hex]
|
110 |
|
|
}
|
111 |
|
|
if (!Array.isArray(hex) || hex.length === 0 || hex.some(function (h) {
|
112 |
|
|
return typeof h !== 'string'
|
113 |
|
|
})) {
|
114 |
|
|
throw new Error('The value of `' + key + '` property must be an Array and each item could only be a hex string, e.g.: FF0000')
|
115 |
|
|
}
|
116 |
|
|
var defHexColor = _defColors[key]
|
117 |
|
|
if (!hex[0]) {
|
118 |
|
|
hex[0] = defHexColor[0]
|
119 |
|
|
}
|
120 |
|
|
if (hex.length === 1 || !hex[1]) {
|
121 |
|
|
hex = [hex[0]]
|
122 |
|
|
hex.push(defHexColor[1])
|
123 |
|
|
}
|
124 |
|
|
|
125 |
|
|
hex = hex.slice(0, 2)
|
126 |
|
|
} else if (typeof hex !== 'string') {
|
127 |
|
|
throw new Error('The value of `' + key + '` property must be a hex string, e.g.: FF0000')
|
128 |
|
|
}
|
129 |
|
|
_finalColors[key] = hex
|
130 |
|
|
}
|
131 |
|
|
_setTags(_finalColors)
|
132 |
|
|
}
|
133 |
|
|
|
134 |
|
|
/**
|
135 |
|
|
* Reset colors.
|
136 |
|
|
*/
|
137 |
|
|
ansiHTML.reset = function () {
|
138 |
|
|
_setTags(_defColors)
|
139 |
|
|
}
|
140 |
|
|
|
141 |
|
|
/**
|
142 |
|
|
* Expose tags, including open and close.
|
143 |
|
|
* @type {Object}
|
144 |
|
|
*/
|
145 |
|
|
ansiHTML.tags = {}
|
146 |
|
|
|
147 |
|
|
if (Object.defineProperty) {
|
148 |
|
|
Object.defineProperty(ansiHTML.tags, 'open', {
|
149 |
|
|
get: function () { return _openTags }
|
150 |
|
|
})
|
151 |
|
|
Object.defineProperty(ansiHTML.tags, 'close', {
|
152 |
|
|
get: function () { return _closeTags }
|
153 |
|
|
})
|
154 |
|
|
} else {
|
155 |
|
|
ansiHTML.tags.open = _openTags
|
156 |
|
|
ansiHTML.tags.close = _closeTags
|
157 |
|
|
}
|
158 |
|
|
|
159 |
|
|
function _setTags (colors) {
|
160 |
|
|
// reset all
|
161 |
|
|
_openTags['0'] = 'font-weight:normal;opacity:1;color:#' + colors.reset[0] + ';background:#' + colors.reset[1]
|
162 |
|
|
// inverse
|
163 |
|
|
_openTags['7'] = 'color:#' + colors.reset[1] + ';background:#' + colors.reset[0]
|
164 |
|
|
// dark grey
|
165 |
|
|
_openTags['90'] = 'color:#' + colors.darkgrey
|
166 |
|
|
|
167 |
|
|
for (var code in _styles) {
|
168 |
|
|
var color = _styles[code]
|
169 |
|
|
var oriColor = colors[color] || '000'
|
170 |
|
|
_openTags[code] = 'color:#' + oriColor
|
171 |
|
|
code = parseInt(code)
|
172 |
|
|
_openTags[(code + 10).toString()] = 'background:#' + oriColor
|
173 |
|
|
}
|
174 |
|
|
}
|
175 |
|
|
|
176 |
|
|
ansiHTML.reset()
|