ansi-to-html
Advanced tools
Comparing version 0.5.0 to 0.6.0
/*global module:false*/ | ||
module.exports = function(grunt) { | ||
module.exports = function (grunt) { | ||
grunt.loadNpmTasks('grunt-contrib-watch'); | ||
grunt.loadNpmTasks('grunt-contrib-coffee'); | ||
grunt.loadNpmTasks('grunt-simple-mocha'); | ||
grunt.loadNpmTasks('grunt-contrib-watch'); | ||
grunt.loadNpmTasks('grunt-simple-mocha'); | ||
grunt.loadNpmTasks('grunt-eslint'); | ||
// Project configuration. | ||
grunt.initConfig({ | ||
simplemocha: { | ||
all: ['test/ansi_to_html.js'], | ||
options: {reporter: 'tap'} | ||
}, | ||
coffee: { | ||
src: { | ||
src: 'src/ansi_to_html.coffee', | ||
dest: 'lib/ansi_to_html.js' | ||
}, | ||
cli: { | ||
src: 'src/cli.coffee', | ||
dest: 'lib/cli.js' | ||
}, | ||
test: { | ||
src: 'test/ansi_to_html.coffee', | ||
dest: 'test/ansi_to_html.js' | ||
} | ||
}, | ||
watch: { | ||
files: ['src/**/*.coffee', 'test/**/*.coffee'], | ||
tasks: 'default' | ||
} | ||
}); | ||
// Project configuration. | ||
grunt.initConfig({ | ||
eslint: { | ||
options: { configFile: '.eslintrc.json' }, | ||
target: ['lib/**/*.js', 'test/**/*.js'] | ||
}, | ||
simplemocha: { | ||
all: ['test/ansi_to_html.js', ['test/cli.js']], | ||
options: {reporter: 'tap'} | ||
}, | ||
watch: { | ||
files: ['src/**/*.js', 'test/**/*.js'], | ||
tasks: 'default' | ||
} | ||
}); | ||
// Default task. | ||
grunt.registerTask('default', ['coffee', 'simplemocha']); | ||
// Default task. | ||
grunt.registerTask('default', ['simplemocha']); | ||
}; |
@@ -1,406 +0,461 @@ | ||
(function() { | ||
var Filter, STYLES, defaults, entities, extend, j, results, toHexString, | ||
slice = [].slice; | ||
const entities = require('entities'); | ||
const defaults = { | ||
fg: '#FFF', | ||
bg: '#000', | ||
newline: false, | ||
escapeXML: false, | ||
stream: false, | ||
colors: getDefaultColors() | ||
}; | ||
entities = require("entities"); | ||
function getDefaultColors() { | ||
const colors = { | ||
0: '#000', | ||
1: '#A00', | ||
2: '#0A0', | ||
3: '#A50', | ||
4: '#00A', | ||
5: '#A0A', | ||
6: '#0AA', | ||
7: '#AAA', | ||
8: '#555', | ||
9: '#F55', | ||
10: '#5F5', | ||
11: '#FF5', | ||
12: '#55F', | ||
13: '#F5F', | ||
14: '#5FF', | ||
15: '#FFF' | ||
}; | ||
STYLES = { | ||
'ef0': 'color:#000', | ||
'ef1': 'color:#A00', | ||
'ef2': 'color:#0A0', | ||
'ef3': 'color:#A50', | ||
'ef4': 'color:#00A', | ||
'ef5': 'color:#A0A', | ||
'ef6': 'color:#0AA', | ||
'ef7': 'color:#AAA', | ||
'ef8': 'color:#555', | ||
'ef9': 'color:#F55', | ||
'ef10': 'color:#5F5', | ||
'ef11': 'color:#FF5', | ||
'ef12': 'color:#55F', | ||
'ef13': 'color:#F5F', | ||
'ef14': 'color:#5FF', | ||
'ef15': 'color:#FFF', | ||
'eb0': 'background-color:#000', | ||
'eb1': 'background-color:#A00', | ||
'eb2': 'background-color:#0A0', | ||
'eb3': 'background-color:#A50', | ||
'eb4': 'background-color:#00A', | ||
'eb5': 'background-color:#A0A', | ||
'eb6': 'background-color:#0AA', | ||
'eb7': 'background-color:#AAA', | ||
'eb8': 'background-color:#555', | ||
'eb9': 'background-color:#F55', | ||
'eb10': 'background-color:#5F5', | ||
'eb11': 'background-color:#FF5', | ||
'eb12': 'background-color:#55F', | ||
'eb13': 'background-color:#F5F', | ||
'eb14': 'background-color:#5FF', | ||
'eb15': 'background-color:#FFF' | ||
}; | ||
range(0, 5).forEach(red => { | ||
range(0, 5).forEach(green => { | ||
range(0, 5).forEach(blue => setStyleColor(red, green, blue, colors)); | ||
}); | ||
}); | ||
toHexString = function(num) { | ||
num = num.toString(16); | ||
while (num.length < 2) { | ||
num = "0" + num; | ||
} | ||
return num; | ||
}; | ||
range(0, 23).forEach(function (gray) { | ||
const c = gray + 232; | ||
const l = toHexString(gray * 10 + 8); | ||
[0, 1, 2, 3, 4, 5].forEach(function(red) { | ||
return [0, 1, 2, 3, 4, 5].forEach(function(green) { | ||
return [0, 1, 2, 3, 4, 5].forEach(function(blue) { | ||
var b, c, g, n, r, rgb; | ||
c = 16 + (red * 36) + (green * 6) + blue; | ||
r = red > 0 ? red * 40 + 55 : 0; | ||
g = green > 0 ? green * 40 + 55 : 0; | ||
b = blue > 0 ? blue * 40 + 55 : 0; | ||
rgb = ((function() { | ||
var j, len, ref, results; | ||
ref = [r, g, b]; | ||
results = []; | ||
for (j = 0, len = ref.length; j < len; j++) { | ||
n = ref[j]; | ||
results.push(toHexString(n)); | ||
} | ||
return results; | ||
})()).join(''); | ||
STYLES["ef" + c] = "color:#" + rgb; | ||
return STYLES["eb" + c] = "background-color:#" + rgb; | ||
}); | ||
colors[c] = '#' + l + l + l; | ||
}); | ||
}); | ||
(function() { | ||
results = []; | ||
for (j = 0; j <= 23; j++){ results.push(j); } | ||
return results; | ||
}).apply(this).forEach(function(gray) { | ||
var c, l; | ||
c = gray + 232; | ||
l = toHexString(gray * 10 + 8); | ||
STYLES["ef" + c] = "color:#" + l + l + l; | ||
return STYLES["eb" + c] = "background-color:#" + l + l + l; | ||
}); | ||
return colors; | ||
} | ||
extend = function() { | ||
var dest, k, len, o, obj, objs, v; | ||
dest = arguments[0], objs = 2 <= arguments.length ? slice.call(arguments, 1) : []; | ||
for (o = 0, len = objs.length; o < len; o++) { | ||
obj = objs[o]; | ||
for (k in obj) { | ||
v = obj[k]; | ||
dest[k] = v; | ||
} | ||
/** | ||
* @param {number} red | ||
* @param {number} green | ||
* @param {number} blue | ||
* @param {object} colors | ||
*/ | ||
function setStyleColor(red, green, blue, colors) { | ||
const c = 16 + (red * 36) + (green * 6) + blue; | ||
const r = red > 0 ? red * 40 + 55 : 0; | ||
const g = green > 0 ? green * 40 + 55 : 0; | ||
const b = blue > 0 ? blue * 40 + 55 : 0; | ||
colors[c] = toColorHexString([r, g, b]); | ||
} | ||
/** | ||
* Converts from a number like 15 to a hex string like 'F' | ||
* @param {number} num | ||
* @returns {string} | ||
*/ | ||
function toHexString(num) { | ||
var str = num.toString(16); | ||
while (str.length < 2) { | ||
str = '0' + str; | ||
} | ||
return dest; | ||
}; | ||
defaults = { | ||
fg: '#FFF', | ||
bg: '#000', | ||
newline: false, | ||
escapeXML: false, | ||
stream: false | ||
}; | ||
return str; | ||
} | ||
Filter = (function() { | ||
function Filter(options) { | ||
if (options == null) { | ||
options = {}; | ||
} | ||
this.opts = extend({}, defaults, options); | ||
this.input = []; | ||
this.stack = []; | ||
this.stickyStack = []; | ||
/** | ||
* Converts from an array of numbers like [15, 15, 15] to a hex string like 'FFF' | ||
* @param {[red, green, blue]} ref | ||
* @returns {string} | ||
*/ | ||
function toColorHexString(ref) { | ||
var results = []; | ||
for (var j = 0, len = ref.length; j < len; j++) { | ||
results.push(toHexString(ref[j])); | ||
} | ||
Filter.prototype.toHtml = function(input) { | ||
var buf; | ||
this.input = typeof input === 'string' ? [input] : input; | ||
buf = []; | ||
this.stickyStack.forEach((function(_this) { | ||
return function(element) { | ||
return _this.generateOutput(element.token, element.data, function(chunk) { | ||
return buf.push(chunk); | ||
}); | ||
}; | ||
})(this)); | ||
this.forEach(function(chunk) { | ||
return buf.push(chunk); | ||
}); | ||
this.input = []; | ||
return buf.join(''); | ||
}; | ||
return '#' + results.join(''); | ||
} | ||
Filter.prototype.forEach = function(callback) { | ||
var buf; | ||
buf = ''; | ||
this.input.forEach((function(_this) { | ||
return function(chunk) { | ||
buf += chunk; | ||
return _this.tokenize(buf, function(token, data) { | ||
_this.generateOutput(token, data, callback); | ||
if (_this.opts.stream) { | ||
return _this.updateStickyStack(token, data); | ||
} | ||
}); | ||
}; | ||
})(this)); | ||
if (this.stack.length) { | ||
return callback(this.resetStyles()); | ||
} | ||
}; | ||
/** | ||
* @param {Array} stack | ||
* @param {string} token | ||
* @param {*} data | ||
* @param {object} options | ||
*/ | ||
function generateOutput(stack, token, data, options) { | ||
var result; | ||
Filter.prototype.generateOutput = function(token, data, callback) { | ||
switch (token) { | ||
case 'text': | ||
return callback(this.pushText(data)); | ||
case 'display': | ||
return this.handleDisplay(data, callback); | ||
case 'xterm256': | ||
return callback(this.pushStyle("ef" + data)); | ||
} | ||
}; | ||
if (token === 'text') { | ||
result = pushText(data, options); | ||
} else if (token === 'display') { | ||
result = handleDisplay(stack, data, options); | ||
} else if (token === 'xterm256') { | ||
result = pushForegroundColor(stack, options.colors[data]); | ||
} | ||
Filter.prototype.updateStickyStack = function(token, data) { | ||
var notCategory; | ||
notCategory = function(category) { | ||
return function(e) { | ||
return (category === null || e.category !== category) && category !== 'all'; | ||
}; | ||
}; | ||
if (token !== 'text') { | ||
this.stickyStack = this.stickyStack.filter(notCategory(this.categoryForCode(data))); | ||
return this.stickyStack.push({ | ||
token: token, | ||
data: data, | ||
category: this.categoryForCode(data) | ||
}); | ||
} | ||
return result; | ||
} | ||
/** | ||
* @param {Array} stack | ||
* @param {number} code | ||
* @param {object} options | ||
* @returns {*} | ||
*/ | ||
function handleDisplay(stack, code, options) { | ||
code = parseInt(code, 10); | ||
var result; | ||
const codeMap = { | ||
'-1': () => '<br/>', | ||
0: () => stack.length && resetStyles(stack), | ||
1: () => pushTag(stack, 'b'), | ||
3: () => pushTag(stack, 'i'), | ||
4: () => pushTag(stack, 'u'), | ||
8: () => pushStyle(stack, 'display:none'), | ||
9: () => pushTag(stack, 'strike'), | ||
22: () => closeTag(stack, 'b'), | ||
23: () => closeTag(stack, 'i'), | ||
24: () => closeTag(stack, 'u'), | ||
39: () => pushForegroundColor(stack, options.fg), | ||
49: () => pushBackgroundColor(stack, options.bg) | ||
}; | ||
Filter.prototype.handleDisplay = function(code, callback) { | ||
code = parseInt(code, 10); | ||
if (code === -1) { | ||
callback('<br/>'); | ||
} | ||
if (code === 0) { | ||
if (this.stack.length) { | ||
callback(this.resetStyles()); | ||
} | ||
} | ||
if (code === 1) { | ||
callback(this.pushTag('b')); | ||
} | ||
if (code === 2) { | ||
if (codeMap[code]) { | ||
result = codeMap[code](); | ||
} else if (4 < code && code < 7) { | ||
result = pushTag(stack, 'blink'); | ||
} else if (29 < code && code < 38) { | ||
result = pushForegroundColor(stack, options.colors[code - 30]); | ||
} else if ((39 < code && code < 48)) { | ||
result = pushBackgroundColor(stack, options.colors[code - 40]); | ||
} else if ((89 < code && code < 98)) { | ||
result = pushForegroundColor(stack, options.colors[8 + (code - 90)]); | ||
} else if ((99 < code && code < 108)) { | ||
result = pushBackgroundColor(stack, options.colors[8 + (code - 100)]); | ||
} | ||
} | ||
if (code === 3) { | ||
callback(this.pushTag('i')); | ||
} | ||
if (code === 4) { | ||
callback(this.pushTag('u')); | ||
} | ||
if ((4 < code && code < 7)) { | ||
callback(this.pushTag('blink')); | ||
} | ||
if (code === 7) { | ||
return result; | ||
} | ||
} | ||
if (code === 8) { | ||
callback(this.pushStyle('display:none')); | ||
} | ||
if (code === 9) { | ||
callback(this.pushTag('strike')); | ||
} | ||
if (code === 22) { | ||
callback(this.closeTag('b')); | ||
} | ||
if (code === 23) { | ||
callback(this.closeTag('i')); | ||
} | ||
if (code === 24) { | ||
callback(this.closeTag('u')); | ||
} | ||
if ((29 < code && code < 38)) { | ||
callback(this.pushStyle("ef" + (code - 30))); | ||
} | ||
if (code === 39) { | ||
callback(this.pushStyle("color:" + this.opts.fg)); | ||
} | ||
if ((39 < code && code < 48)) { | ||
callback(this.pushStyle("eb" + (code - 40))); | ||
} | ||
if (code === 49) { | ||
callback(this.pushStyle("background-color:" + this.opts.bg)); | ||
} | ||
if ((89 < code && code < 98)) { | ||
callback(this.pushStyle("ef" + (8 + (code - 90)))); | ||
} | ||
if ((99 < code && code < 108)) { | ||
return callback(this.pushStyle("eb" + (8 + (code - 100)))); | ||
} | ||
}; | ||
/** | ||
* Clear all the styles | ||
* @returns {string} | ||
*/ | ||
function resetStyles(stack) { | ||
var stackClone = stack.slice(0); | ||
Filter.prototype.categoryForCode = function(code) { | ||
code = parseInt(code, 10); | ||
if (code === 0) { | ||
return 'all'; | ||
} else if (code === 1) { | ||
return 'bold'; | ||
} else if ((2 < code && code < 5)) { | ||
return 'underline'; | ||
} else if ((4 < code && code < 7)) { | ||
return 'blink'; | ||
} else if (code === 8) { | ||
return 'hide'; | ||
} else if (code === 9) { | ||
return 'strike'; | ||
} else if ((29 < code && code < 38) || code === 39 || (89 < code && code < 98)) { | ||
return 'foreground-color'; | ||
} else if ((39 < code && code < 48) || code === 49 || (99 < code && code < 108)) { | ||
return 'background-color'; | ||
} else { | ||
return null; | ||
} | ||
}; | ||
stack.length = 0; | ||
Filter.prototype.pushTag = function(tag, style) { | ||
if (style == null) { | ||
style = ''; | ||
} | ||
if (style.length && style.indexOf(':') === -1) { | ||
style = STYLES[style]; | ||
} | ||
this.stack.push(tag); | ||
return ["<" + tag, (style ? " style=\"" + style + "\"" : void 0), ">"].join(''); | ||
return stackClone.reverse().map(function (tag) { | ||
return '</' + tag + '>'; | ||
}).join(''); | ||
} | ||
/** | ||
* Creates an array of numbers ranging from low to high | ||
* @param {number} low | ||
* @param {number} high | ||
* @returns {Array} | ||
* @example range(3, 7); // creates [3, 4, 5, 6, 7] | ||
*/ | ||
function range(low, high) { | ||
const results = []; | ||
for (var j = low; j <= high; j++) { | ||
results.push(j); | ||
} | ||
return results; | ||
} | ||
/** | ||
* Returns a new function that is true if value is NOT the same category | ||
* @param {string} category | ||
* @returns {function} | ||
*/ | ||
function notCategory(category) { | ||
return function (e) { | ||
return (category === null || e.category !== category) && category !== 'all'; | ||
}; | ||
} | ||
Filter.prototype.pushText = function(text) { | ||
if (this.opts.escapeXML) { | ||
/** | ||
* Converts a code into an ansi token type | ||
* @param {number} code | ||
* @returns {string} | ||
*/ | ||
function categoryForCode(code) { | ||
code = parseInt(code, 10); | ||
var result = null; | ||
if (code === 0) { | ||
result = 'all'; | ||
} else if (code === 1) { | ||
result = 'bold'; | ||
} else if ((2 < code && code < 5)) { | ||
result = 'underline'; | ||
} else if ((4 < code && code < 7)) { | ||
result = 'blink'; | ||
} else if (code === 8) { | ||
result = 'hide'; | ||
} else if (code === 9) { | ||
result = 'strike'; | ||
} else if ((29 < code && code < 38) || code === 39 || (89 < code && code < 98)) { | ||
result = 'foreground-color'; | ||
} else if ((39 < code && code < 48) || code === 49 || (99 < code && code < 108)) { | ||
result = 'background-color'; | ||
} | ||
return result; | ||
} | ||
/** | ||
* @param {string} text | ||
* @param {object} options | ||
* @returns {string} | ||
*/ | ||
function pushText(text, options) { | ||
if (options.escapeXML) { | ||
return entities.encodeXML(text); | ||
} else { | ||
return text; | ||
} | ||
}; | ||
} | ||
Filter.prototype.pushStyle = function(style) { | ||
return this.pushTag("span", style); | ||
}; | ||
return text; | ||
} | ||
Filter.prototype.closeTag = function(style) { | ||
var last; | ||
if (this.stack.slice(-1)[0] === style) { | ||
last = this.stack.pop(); | ||
} | ||
if (last != null) { | ||
return "</" + style + ">"; | ||
} | ||
}; | ||
/** | ||
* @param {Array} stack | ||
* @param {string} tag | ||
* @param {string} [style=''] | ||
* @returns {string} | ||
*/ | ||
function pushTag(stack, tag, style) { | ||
if (!style) { | ||
style = ''; | ||
} | ||
Filter.prototype.resetStyles = function() { | ||
var ref, stack; | ||
ref = [this.stack, []], stack = ref[0], this.stack = ref[1]; | ||
return stack.reverse().map(function(tag) { | ||
return "</" + tag + ">"; | ||
}).join(''); | ||
}; | ||
stack.push(tag); | ||
Filter.prototype.tokenize = function(text, callback) { | ||
var ansiHandler, ansiMatch, ansiMess, handler, i, len, length, newline, o, process, realText, remove, removeXterm256, results1, tokens; | ||
ansiMatch = false; | ||
ansiHandler = 3; | ||
remove = function(m) { | ||
return ['<' + tag, (style ? ' style="' + style + '"' : void 0), '>'].join(''); | ||
} | ||
/** | ||
* @param {Array} stack | ||
* @param {string} style | ||
* @returns {string} | ||
*/ | ||
function pushStyle (stack, style) { | ||
return pushTag(stack, 'span', style); | ||
} | ||
function pushForegroundColor(stack, color) { | ||
return pushTag(stack, 'span', 'color:' + color); | ||
} | ||
function pushBackgroundColor(stack, color) { | ||
return pushTag(stack, 'span', 'background-color:' + color); | ||
} | ||
/** | ||
* @param {Array} stack | ||
* @param {string} style | ||
* @returns {string} | ||
*/ | ||
function closeTag(stack, style) { | ||
var last; | ||
if (stack.slice(-1)[0] === style) { | ||
last = stack.pop(); | ||
} | ||
if (last) { | ||
return '</' + style + '>'; | ||
} | ||
} | ||
/** | ||
* @param {string} text | ||
* @param {object} options | ||
* @param {function} callback | ||
* @returns {Array} | ||
*/ | ||
function tokenize(text, options, callback) { | ||
var ansiMatch = false; | ||
var ansiHandler = 3; | ||
function remove() { | ||
return ''; | ||
}; | ||
removeXterm256 = function(m, g1) { | ||
} | ||
function removeXterm256(m, g1) { | ||
callback('xterm256', g1); | ||
return ''; | ||
}; | ||
newline = (function(_this) { | ||
return function(m) { | ||
if (_this.opts.newline) { | ||
} | ||
function newline(m) { | ||
if (options.newline) { | ||
callback('display', -1); | ||
} else { | ||
} else { | ||
callback('text', m); | ||
} | ||
return ''; | ||
}; | ||
})(this); | ||
ansiMess = function(m, g1) { | ||
var code, len, o; | ||
} | ||
return ''; | ||
} | ||
function ansiMess(m, g1) { | ||
ansiMatch = true; | ||
if (g1.trim().length === 0) { | ||
g1 = '0'; | ||
g1 = '0'; | ||
} | ||
g1 = g1.trimRight(';').split(';'); | ||
for (o = 0, len = g1.length; o < len; o++) { | ||
code = g1[o]; | ||
callback('display', code); | ||
for (var o = 0, len = g1.length; o < len; o++) { | ||
callback('display', g1[o]); | ||
} | ||
return ''; | ||
}; | ||
realText = function(m) { | ||
} | ||
function realText(m) { | ||
callback('text', m); | ||
return ''; | ||
}; | ||
tokens = [ | ||
{ | ||
pattern: /^\x08+/, | ||
sub: remove | ||
}, { | ||
pattern: /^\x1b\[[012]?K/, | ||
sub: remove | ||
}, { | ||
pattern: /^\x1b\[38;5;(\d+)m/, | ||
sub: removeXterm256 | ||
}, { | ||
pattern: /^\n/, | ||
sub: newline | ||
}, { | ||
pattern: /^\x1b\[((?:\d{1,3};?)+|)m/, | ||
sub: ansiMess | ||
}, { | ||
pattern: /^\x1b\[?[\d;]{0,3}/, | ||
sub: remove | ||
}, { | ||
pattern: /^([^\x1b\x08\n]+)/, | ||
sub: realText | ||
} | ||
]; | ||
process = function(handler, i) { | ||
var matches; | ||
} | ||
/* eslint no-control-regex:0 */ | ||
const tokens = [{ | ||
pattern: /^\x08+/, | ||
sub: remove | ||
}, { | ||
pattern: /^\x1b\[[012]?K/, | ||
sub: remove | ||
}, { | ||
pattern: /^\x1b\[38;5;(\d+)m/, | ||
sub: removeXterm256 | ||
}, { | ||
pattern: /^\n/, | ||
sub: newline | ||
}, { | ||
pattern: /^\x1b\[((?:\d{1,3};?)+|)m/, | ||
sub: ansiMess | ||
}, { | ||
pattern: /^\x1b\[?[\d;]{0,3}/, | ||
sub: remove | ||
}, { | ||
pattern: /^([^\x1b\x08\n]+)/, | ||
sub: realText | ||
}]; | ||
function process(handler, i) { | ||
if (i > ansiHandler && ansiMatch) { | ||
return; | ||
} else { | ||
ansiMatch = false; | ||
return; | ||
} | ||
matches = text.match(handler.pattern); | ||
ansiMatch = false; | ||
text = text.replace(handler.pattern, handler.sub); | ||
if (matches == null) { | ||
} | ||
var handler; | ||
var results1 = []; | ||
var length = text.length; | ||
while (length > 0) { | ||
for (var i = 0, o = 0, len = tokens.length; o < len; i = ++o) { | ||
handler = tokens[i]; | ||
process(handler, i); | ||
} | ||
}; | ||
results1 = []; | ||
while ((length = text.length) > 0) { | ||
for (i = o = 0, len = tokens.length; o < len; i = ++o) { | ||
handler = tokens[i]; | ||
process(handler, i); | ||
} | ||
if (text.length === length) { | ||
break; | ||
break; | ||
} else { | ||
results1.push(void 0); | ||
results1.push(0); | ||
} | ||
} | ||
return results1; | ||
}; | ||
return Filter; | ||
length = text.length; | ||
} | ||
})(); | ||
return results1; | ||
} | ||
module.exports = Filter; | ||
/** | ||
* If streaming, then the stack is "sticky" | ||
* | ||
* @param {Array} stickyStack | ||
* @param {string} token | ||
* @param {*} data | ||
* @returns {Array} | ||
*/ | ||
function updateStickyStack(stickyStack, token, data) { | ||
if (token !== 'text') { | ||
stickyStack = stickyStack.filter(notCategory(categoryForCode(data))); | ||
stickyStack.push({token: token, data: data, category: categoryForCode(data)}); | ||
} | ||
}).call(this); | ||
return stickyStack; | ||
} | ||
function Filter(options) { | ||
options = options || {}; | ||
if (options.colors) { | ||
options.colors = Object.assign({}, defaults.colors, options.colors); | ||
} | ||
this.opts = Object.assign({}, defaults, options); | ||
this.stack = []; | ||
this.stickyStack = []; | ||
} | ||
Filter.prototype = { | ||
toHtml (input) { | ||
input = typeof input === 'string' ? [input] : input; | ||
const stack = this.stack; | ||
const options = this.opts; | ||
const buf = []; | ||
this.stickyStack.forEach(element => { | ||
var output = generateOutput(stack, element.token, element.data, options); | ||
if (output) { | ||
buf.push(output); | ||
} | ||
}); | ||
tokenize(input.join(''), options, (token, data) => { | ||
var output = generateOutput(stack, token, data, options); | ||
if (output) { | ||
buf.push(output); | ||
} | ||
if (options.stream) { | ||
this.stickyStack = updateStickyStack(this.stickyStack, token, data); | ||
} | ||
}); | ||
if (stack.length) { | ||
buf.push(resetStyles(stack)); | ||
} | ||
return buf.join(''); | ||
} | ||
}; | ||
module.exports = Filter; |
110
lib/cli.js
@@ -1,71 +0,63 @@ | ||
(function() { | ||
var args, convert, file, help, htmlStream, i, j, ref, skip, stream; | ||
/* eslint no-console:0 */ | ||
const help = '\nuasge: ansi-to-html [options] [file]\n \nfile: The file to display or stdin\n \noptions: \n \n -f, --fg The background color used for resets (#000)\n -b, --bg The foreground color used for resets (#FFF)\n -n, --newline Convert newline characters to <br/> (false)\n -x, --escapeXML Generate XML entities (false)\n -v, --version Print version\n -h, --help Print help\n '; | ||
var file = null, | ||
skip = false, | ||
args = { | ||
stream: true | ||
}; | ||
help = "\nuasge: ansi-to-html [options] [file]\n \nfile: The file to display or stdin\n \noptions: \n \n -f, --fg The background color used for resets (#000)\n -b, --bg The foreground color used for resets (#FFF)\n -n, --newline Convert newline characters to <br/> (false)\n -x, --escapeXML Generate XML entities (false)\n -v, --version Print version\n -h, --help Print help\n "; | ||
file = null; | ||
skip = false; | ||
args = { | ||
stream: true | ||
}; | ||
for (i = j = 2, ref = process.argv.length; 2 <= ref ? j < ref : j > ref; i = 2 <= ref ? ++j : --j) { | ||
for (var i = 2, j = 2, ref = process.argv.length; 2 <= ref ? j < ref : j > ref; i = 2 <= ref ? ++j : --j) { | ||
if (skip) { | ||
skip = false; | ||
continue; | ||
skip = false; | ||
continue; | ||
} | ||
switch (process.argv[i]) { | ||
case '-n': | ||
case '--newline': | ||
args.newline = true; | ||
break; | ||
case '-x': | ||
case '--escapeXML': | ||
args.escapeXML = true; | ||
break; | ||
case '-f': | ||
case '--fg': | ||
args.fg = process.argv[i + 1]; | ||
skip = true; | ||
break; | ||
case '-b': | ||
case '--bg': | ||
args.bg = process.argv[i + 1]; | ||
skip = true; | ||
break; | ||
case '-v': | ||
case '--version': | ||
console.log(require(__dirname + "/../package.json").version); | ||
process.exit(0); | ||
break; | ||
case '-h': | ||
case '--help': | ||
console.log(help); | ||
process.exit(0); | ||
break; | ||
default: | ||
file = process.argv[i]; | ||
case '-n': | ||
case '--newline': | ||
args.newline = true; | ||
break; | ||
case '-x': | ||
case '--escapeXML': | ||
args.escapeXML = true; | ||
break; | ||
case '-f': | ||
case '--fg': | ||
args.fg = process.argv[i + 1]; | ||
skip = true; | ||
break; | ||
case '-b': | ||
case '--bg': | ||
args.bg = process.argv[i + 1]; | ||
skip = true; | ||
break; | ||
case '-v': | ||
case '--version': | ||
console.log(require(__dirname + '/../package.json').version); | ||
process.exit(0); | ||
break; | ||
case '-h': | ||
case '--help': | ||
console.log(help); | ||
process.exit(0); | ||
break; | ||
default: | ||
file = process.argv[i]; | ||
} | ||
} | ||
} | ||
convert = new (require('../'))(args); | ||
var convert = new (require('./ansi_to_html.js'))(args); | ||
htmlStream = function(stream) { | ||
return stream.on('data', function(chunk) { | ||
return process.stdout.write(convert.toHtml(chunk)); | ||
var htmlStream = function (stream) { | ||
return stream.on('data', function (chunk) { | ||
return process.stdout.write(convert.toHtml(chunk)); | ||
}); | ||
}; | ||
}; | ||
if (file) { | ||
stream = require('fs').createReadStream(file, { | ||
encoding: 'utf8' | ||
}); | ||
if (file) { | ||
var stream = require('fs').createReadStream(file, {encoding: 'utf8'}); | ||
htmlStream(stream); | ||
} else { | ||
} else { | ||
process.stdin.setEncoding('utf8'); | ||
htmlStream(process.stdin); | ||
} | ||
}).call(this); | ||
} |
{ | ||
"name": "ansi-to-html", | ||
"version": "0.5.0", | ||
"version": "0.6.0", | ||
"description": "Convert ansi escaped text streams to html.", | ||
"main": "lib/ansi_to_html.js", | ||
"engines": { "node": "*" }, | ||
"engines": { | ||
"node": "*" | ||
}, | ||
"scripts": { | ||
"test": "grunt simplemocha" | ||
"lint": "./node_modules/eslint/bin/eslint.js lib test", | ||
"test": "./node_modules/mocha/bin/mocha --reporter tap" | ||
}, | ||
@@ -26,19 +29,25 @@ "repository": { | ||
}, | ||
"contributors": [{ | ||
"name": "Michael", | ||
"email": "michael@riesd.com" | ||
}, { | ||
"name": "Thorsten Kohnhorst", | ||
"email": "monsterkodi@gmx.net" | ||
}, { | ||
"name": "Yoram Grahame", | ||
"email": "yoz@yoz.com" | ||
}], | ||
"license": "MIT", | ||
"contributors": [ | ||
{ | ||
"name": "Dane Stuckel", | ||
"email": "dane.stuckel@gmail.com" | ||
}, | ||
{ | ||
"name": "Michael", | ||
"email": "michael@riesd.com" | ||
}, | ||
{ | ||
"name": "Thorsten Kohnhorst", | ||
"email": "monsterkodi@gmx.net" | ||
}, | ||
{ | ||
"name": "Yoram Grahame", | ||
"email": "yoz@yoz.com" | ||
} | ||
], | ||
"license": "MIT", | ||
"devDependencies": { | ||
"chai": "~3.5.0", | ||
"grunt": "~0.4.5", | ||
"grunt-contrib-coffee": "^0.13.0", | ||
"grunt-contrib-watch": "~0.6.1", | ||
"grunt-simple-mocha": "~0.4.1" | ||
"eslint": "^3.13.1", | ||
"mocha": "^3.2.0" | ||
}, | ||
@@ -45,0 +54,0 @@ "dependencies": { |
@@ -60,10 +60,14 @@ ## Ansi to Html | ||
**colors** <code>Object/Array with values 0 - 255 containing CSS color values</code> Can override specific colors or the entire ANSI palette | ||
### Default options | ||
```coffee | ||
fg: '#FFF' | ||
bg: '#000' | ||
newline: false | ||
escapeXML: false | ||
stream: false | ||
```javascript | ||
{ | ||
fg: '#FFF', | ||
bg: '#000', | ||
newline: false, | ||
escapeXML: false, | ||
stream: false | ||
} | ||
``` | ||
@@ -81,17 +85,8 @@ | ||
If you don't have it already, install the grunt command-line tool: | ||
Lint | ||
npm install -g grunt-cli | ||
npm run lint | ||
Build and test | ||
Test | ||
grunt | ||
All the time | ||
grunt watch | ||
Or separately | ||
grunt coffee | ||
grunt simplemocha # or npm test | ||
npm test |
@@ -1,274 +0,352 @@ | ||
(function() { | ||
var Filter, expect, test; | ||
/* globals describe, it*/ | ||
Filter = require('../lib/ansi_to_html.js'); | ||
const Filter = require('../lib/ansi_to_html.js'); | ||
const expect = require('chai').expect; | ||
expect = require('chai').expect; | ||
function test(text, result, done, opts) { | ||
if (!opts) { | ||
opts = {}; | ||
} | ||
test = function(text, result, done, opts) { | ||
var f, filtered; | ||
if (opts == null) { | ||
opts = {}; | ||
var f = new Filter(opts); | ||
function filtered(memo, t) { | ||
return memo + f.toHtml(t); | ||
} | ||
f = new Filter(opts); | ||
filtered = function(memo, t) { | ||
return memo += f.toHtml(t); | ||
}; | ||
text = typeof text.reduce === 'function' ? text : [text]; | ||
expect(text.reduce(filtered, '')).to.equal(result); | ||
return done(); | ||
}; | ||
} | ||
describe('ansi to html', function() { | ||
describe('constructed with no options', function() { | ||
it("doesn't modify the input string", function(done) { | ||
var result, text; | ||
text = result = 'some text'; | ||
return test(text, result, done); | ||
}); | ||
it('returns plain text when given plain text', function(done) { | ||
var result, text; | ||
text = 'test\ntest\n'; | ||
result = 'test\ntest\n'; | ||
return test(text, result, done); | ||
}); | ||
it('renders foreground colors', function(done) { | ||
var result, text; | ||
text = "colors: \x1b[30mblack\x1b[37mwhite"; | ||
result = 'colors: <span style="color:#000">black<span style="color:' + '#AAA">white</span></span>'; | ||
return test(text, result, done); | ||
}); | ||
it('renders light foreground colors', function(done) { | ||
var result, text; | ||
text = 'colors: \x1b[90mblack\x1b[97mwhite'; | ||
result = 'colors: <span style="color:#555">black<span style="color:' + '#FFF">white</span></span>'; | ||
return test(text, result, done); | ||
}); | ||
it('renders background colors', function(done) { | ||
var result, text; | ||
text = 'colors: \x1b[40mblack\x1b[47mwhite'; | ||
result = 'colors: <span style="background-color:#000">black<span ' + 'style="background-color:#AAA">white</span></span>'; | ||
return test(text, result, done); | ||
}); | ||
it('renders light background colors', function(done) { | ||
var result, text; | ||
text = 'colors: \x1b[100mblack\x1b[107mwhite'; | ||
result = 'colors: <span style="background-color:#555">black<span ' + 'style="background-color:#FFF">white</span></span>'; | ||
return test(text, result, done); | ||
}); | ||
it('renders strikethrough', function(done) { | ||
var result, text; | ||
text = 'strike: \x1b[9mthat'; | ||
result = 'strike: <strike>that</strike>'; | ||
return test(text, result, done); | ||
}); | ||
it('renders blink', function(done) { | ||
var result, text; | ||
text = 'blink: \x1b[5mwhat'; | ||
result = 'blink: <blink>what</blink>'; | ||
return test(text, result, done); | ||
}); | ||
it('renders underline', function(done) { | ||
var result, text; | ||
text = 'underline: \x1b[4mstuff'; | ||
result = 'underline: <u>stuff</u>'; | ||
return test(text, result, done); | ||
}); | ||
it('renders bold', function(done) { | ||
var result, text; | ||
text = 'bold: \x1b[1mstuff'; | ||
result = 'bold: <b>stuff</b>'; | ||
return test(text, result, done); | ||
}); | ||
it('renders italic', function(done) { | ||
var result, text; | ||
text = 'italic: \x1b[3mstuff'; | ||
result = 'italic: <i>stuff</i>'; | ||
return test(text, result, done); | ||
}); | ||
it('handles ressets', function(done) { | ||
var result, text; | ||
text = '\x1b[1mthis is bold\x1b[0m, but this isn\'t'; | ||
result = '<b>this is bold</b>, but this isn\'t'; | ||
return test(text, result, done); | ||
}); | ||
it('handles multiple resets', function(done) { | ||
var result, text; | ||
text = 'normal, \x1b[1mbold, \x1b[4munderline, \x1b[31mred\x1b[0m, normal'; | ||
result = 'normal, <b>bold, <u>underline, <span style="color:' + '#A00">red</span></u></b>, normal'; | ||
return test(text, result, done); | ||
}); | ||
it('handles resets with implicit 0', function(done) { | ||
var result, text; | ||
text = '\x1b[1mthis is bold\x1b[m, but this isn\'t'; | ||
result = '<b>this is bold</b>, but this isn\'t'; | ||
return test(text, result, done); | ||
}); | ||
it('renders multi-attribute sequences', function(done) { | ||
var result, text; | ||
text = 'normal, \x1b[1;4;31mbold, underline, and red\x1b[0m, normal'; | ||
result = 'normal, <b><u><span style="color:#A00">bold, underline,' + ' and red</span></u></b>, normal'; | ||
return test(text, result, done); | ||
}); | ||
it('renders multi-attribute sequences with a semi-colon', function(done) { | ||
var result, text; | ||
text = 'normal, \x1b[1;4;31;mbold, underline, and red\x1b[0m, normal'; | ||
result = 'normal, <b><u><span style="color:#A00">bold, underline, ' + 'and red</span></u></b>, normal'; | ||
return test(text, result, done); | ||
}); | ||
it('eats malformed sequences', function(done) { | ||
var result, text; | ||
text = '\x1b[25oops forgot the \'m\''; | ||
result = 'oops forgot the \'m\''; | ||
return test(text, result, done); | ||
}); | ||
it('renders xterm 256 sequences', function(done) { | ||
var result, text; | ||
text = '\x1b[38;5;196mhello'; | ||
result = '<span style="color:#ff0000">hello</span>'; | ||
return test(text, result, done); | ||
}); | ||
it('handles resetting to default foreground color', function(done) { | ||
var result, text; | ||
text = '\x1b[30mblack\x1b[39mdefault'; | ||
result = '<span style="color:#000">black<span style="color:#FFF">' + 'default</span></span>'; | ||
return test(text, result, done); | ||
}); | ||
it('handles resetting to default background color', function(done) { | ||
var result, text; | ||
text = '\x1b[100mblack\x1b[49mdefault'; | ||
result = '<span style="background-color:#555">black<span style=' + '"background-color:#000">default</span></span>'; | ||
return test(text, result, done); | ||
}); | ||
it('is able to disable underline', function(done) { | ||
var result, text; | ||
text = 'underline: \x1b[4mstuff\x1b[24mthings'; | ||
result = 'underline: <u>stuff</u>things'; | ||
return test(text, result, done); | ||
}); | ||
it('is able to skip disabling underline', function(done) { | ||
var result, text; | ||
text = 'not underline: stuff\x1b[24mthings'; | ||
result = 'not underline: stuffthings'; | ||
return test(text, result, done); | ||
}); | ||
it('renders two escape sequences in sequence', function(done) { | ||
var result, text; | ||
text = 'months remaining\x1b[1;31mtimes\x1b[m\x1b[1;32mmultiplied' + ' by\x1b[m $10'; | ||
result = 'months remaining<b><span style="color:#A00">times</span>' + '</b><b><span style="color:#0A0">multiplied by</span></b> $10'; | ||
return test(text, result, done); | ||
}); | ||
it('drops EL code with no parameter', function(done) { | ||
var result, text; | ||
text = '\x1b[Khello'; | ||
result = 'hello'; | ||
return test(text, result, done); | ||
}); | ||
it('drops EL code with 0 parameter', function(done) { | ||
var result, text; | ||
text = '\x1b[0Khello'; | ||
result = 'hello'; | ||
return test(text, result, done); | ||
}); | ||
it('drops EL code with 1 parameter', function(done) { | ||
var result, text; | ||
text = '\x1b[1Khello'; | ||
result = 'hello'; | ||
return test(text, result, done); | ||
}); | ||
it('drops EL code with 2 parameter', function(done) { | ||
var result, text; | ||
text = '\x1b[2Khello'; | ||
result = 'hello'; | ||
return test(text, result, done); | ||
}); | ||
it('renders un-bold code appropriately', function(done) { | ||
var result, text; | ||
text = '\x1b[1mHello\x1b[22m World'; | ||
result = '<b>Hello</b> World'; | ||
return test(text, result, done); | ||
}); | ||
it('skips rendering un-bold code appropriately', function(done) { | ||
var result, text; | ||
text = 'Hello\x1b[22m World'; | ||
result = 'Hello World'; | ||
return test(text, result, done); | ||
}); | ||
it('renders un-italic code appropriately', function(done) { | ||
var result, text; | ||
text = '\x1b[3mHello\x1b[23m World'; | ||
result = '<i>Hello</i> World'; | ||
return test(text, result, done); | ||
}); | ||
return it('skips rendering un-italic code appropriately', function(done) { | ||
var result, text; | ||
text = 'Hello\x1b[23m World'; | ||
result = 'Hello World'; | ||
return test(text, result, done); | ||
}); | ||
describe('ansi to html', function () { | ||
describe('constructed with no options', function () { | ||
it('doesn\'t modify the input string', function (done) { | ||
const text = 'some text'; | ||
const result = 'some text'; | ||
return test(text, result, done); | ||
}); | ||
it('returns plain text when given plain text', function (done) { | ||
const text = 'test\ntest\n'; | ||
const result = 'test\ntest\n'; | ||
return test(text, result, done); | ||
}); | ||
it('renders foreground colors', function (done) { | ||
const text = 'colors: \x1b[30mblack\x1b[37mwhite'; | ||
const result = 'colors: <span style="color:#000">black<span style="color:#AAA">white</span></span>'; | ||
return test(text, result, done); | ||
}); | ||
it('renders light foreground colors', function (done) { | ||
const text = 'colors: \x1b[90mblack\x1b[97mwhite'; | ||
const result = 'colors: <span style="color:#555">black<span style="color:#FFF">white</span></span>'; | ||
return test(text, result, done); | ||
}); | ||
it('renders background colors', function (done) { | ||
const text = 'colors: \x1b[40mblack\x1b[47mwhite'; | ||
const result = 'colors: <span style="background-color:#000">black<span style="background-color:#AAA">white</span></span>'; | ||
return test(text, result, done); | ||
}); | ||
it('renders light background colors', function (done) { | ||
const text = 'colors: \x1b[100mblack\x1b[107mwhite'; | ||
const result = 'colors: <span style="background-color:#555">black<span style="background-color:#FFF">white</span></span>'; | ||
return test(text, result, done); | ||
}); | ||
it('renders strikethrough', function (done) { | ||
const text = 'strike: \x1b[9mthat'; | ||
const result = 'strike: <strike>that</strike>'; | ||
return test(text, result, done); | ||
}); | ||
it('renders blink', function (done) { | ||
const text = 'blink: \x1b[5mwhat'; | ||
const result = 'blink: <blink>what</blink>'; | ||
return test(text, result, done); | ||
}); | ||
it('renders underline', function (done) { | ||
const text = 'underline: \x1b[4mstuff'; | ||
const result = 'underline: <u>stuff</u>'; | ||
return test(text, result, done); | ||
}); | ||
it('renders bold', function (done) { | ||
const text = 'bold: \x1b[1mstuff'; | ||
const result = 'bold: <b>stuff</b>'; | ||
return test(text, result, done); | ||
}); | ||
it('renders italic', function (done) { | ||
const text = 'italic: \x1b[3mstuff'; | ||
const result = 'italic: <i>stuff</i>'; | ||
return test(text, result, done); | ||
}); | ||
it('handles resets', function (done) { | ||
const text = '\x1b[1mthis is bold\x1b[0m, but this isn\'t'; | ||
const result = '<b>this is bold</b>, but this isn\'t'; | ||
return test(text, result, done); | ||
}); | ||
it('handles multiple resets', function (done) { | ||
const text = 'normal, \x1b[1mbold, \x1b[4munderline, \x1b[31mred\x1b[0m, normal'; | ||
const result = 'normal, <b>bold, <u>underline, <span style="color:' + '#A00">red</span></u></b>, normal'; | ||
return test(text, result, done); | ||
}); | ||
it('handles resets with implicit 0', function (done) { | ||
const text = '\x1b[1mthis is bold\x1b[m, but this isn\'t'; | ||
const result = '<b>this is bold</b>, but this isn\'t'; | ||
return test(text, result, done); | ||
}); | ||
it('renders multi-attribute sequences', function (done) { | ||
const text = 'normal, \x1b[1;4;31mbold, underline, and red\x1b[0m, normal'; | ||
const result = 'normal, <b><u><span style="color:#A00">bold, underline,' + ' and red</span></u></b>, normal'; | ||
return test(text, result, done); | ||
}); | ||
it('renders multi-attribute sequences with a semi-colon', function (done) { | ||
const text = 'normal, \x1b[1;4;31;mbold, underline, and red\x1b[0m, normal'; | ||
const result = 'normal, <b><u><span style="color:#A00">bold, underline, and red</span></u></b>, normal'; | ||
return test(text, result, done); | ||
}); | ||
it('eats malformed sequences', function (done) { | ||
const text = '\x1b[25oops forgot the \'m\''; | ||
const result = 'oops forgot the \'m\''; | ||
return test(text, result, done); | ||
}); | ||
it('renders xterm 256 sequences', function (done) { | ||
const text = '\x1b[38;5;196mhello'; | ||
const result = '<span style="color:#ff0000">hello</span>'; | ||
return test(text, result, done); | ||
}); | ||
it('handles resetting to default foreground color', function (done) { | ||
const text = '\x1b[30mblack\x1b[39mdefault'; | ||
const result = '<span style="color:#000">black<span style="color:#FFF">default</span></span>'; | ||
return test(text, result, done); | ||
}); | ||
it('handles resetting to default background color', function (done) { | ||
const text = '\x1b[100mblack\x1b[49mdefault'; | ||
const result = '<span style="background-color:#555">black<span style="background-color:#000">default</span></span>'; | ||
return test(text, result, done); | ||
}); | ||
it('is able to disable underline', function (done) { | ||
const text = 'underline: \x1b[4mstuff\x1b[24mthings'; | ||
const result = 'underline: <u>stuff</u>things'; | ||
return test(text, result, done); | ||
}); | ||
it('is able to skip disabling underline', function (done) { | ||
const text = 'not underline: stuff\x1b[24mthings'; | ||
const result = 'not underline: stuffthings'; | ||
return test(text, result, done); | ||
}); | ||
it('renders two escape sequences in sequence', function (done) { | ||
const text = 'months remaining\x1b[1;31mtimes\x1b[m\x1b[1;32mmultiplied by\x1b[m $10'; | ||
const result = 'months remaining<b><span style="color:#A00">times</span></b><b><span style="color:#0A0">multiplied by</span></b> $10'; | ||
return test(text, result, done); | ||
}); | ||
it('drops EL code with no parameter', function (done) { | ||
const text = '\x1b[Khello'; | ||
const result = 'hello'; | ||
return test(text, result, done); | ||
}); | ||
it('drops EL code with 0 parameter', function (done) { | ||
const text = '\x1b[0Khello'; | ||
const result = 'hello'; | ||
return test(text, result, done); | ||
}); | ||
it('drops EL code with 1 parameter', function (done) { | ||
const text = '\x1b[1Khello'; | ||
const result = 'hello'; | ||
return test(text, result, done); | ||
}); | ||
it('drops EL code with 2 parameter', function (done) { | ||
const text = '\x1b[2Khello'; | ||
const result = 'hello'; | ||
return test(text, result, done); | ||
}); | ||
it('renders un-bold code appropriately', function (done) { | ||
const text = '\x1b[1mHello\x1b[22m World'; | ||
const result = '<b>Hello</b> World'; | ||
return test(text, result, done); | ||
}); | ||
it('skips rendering un-bold code appropriately', function (done) { | ||
const text = 'Hello\x1b[22m World'; | ||
const result = 'Hello World'; | ||
return test(text, result, done); | ||
}); | ||
it('renders un-italic code appropriately', function (done) { | ||
const text = '\x1b[3mHello\x1b[23m World'; | ||
const result = '<i>Hello</i> World'; | ||
return test(text, result, done); | ||
}); | ||
it('skips rendering un-italic code appropriately', function (done) { | ||
const text = 'Hello\x1b[23m World'; | ||
const result = 'Hello World'; | ||
return test(text, result, done); | ||
}); | ||
}); | ||
describe('with escapeXML option enabled', function() { | ||
return it('escapes XML entities', function(done) { | ||
var result, text; | ||
text = 'normal, \x1b[1;4;31;mbold, <underline>, and red\x1b[0m, normal'; | ||
result = 'normal, <b><u><span style="color:#A00">bold, <underline' + '>, and red</span></u></b>, normal'; | ||
return test(text, result, done, { | ||
escapeXML: true | ||
describe('with escapeXML option enabled', function () { | ||
it('escapes XML entities', function (done) { | ||
const text = 'normal, \x1b[1;4;31;mbold, <underline>, and red\x1b[0m, normal'; | ||
const result = 'normal, <b><u><span style="color:#A00">bold, <underline>, and red</span></u></b>, normal'; | ||
return test(text, result, done, {escapeXML: true}); | ||
}); | ||
}); | ||
}); | ||
describe('with newline option enabled', function() { | ||
it('renders line breaks', function(done) { | ||
var result, text; | ||
text = 'test\ntest\n'; | ||
result = 'test<br/>test<br/>'; | ||
return test(text, result, done, { | ||
newline: true | ||
describe('with newline option enabled', function () { | ||
it('renders line breaks', function (done) { | ||
const text = 'test\ntest\n'; | ||
const result = 'test<br/>test<br/>'; | ||
return test(text, result, done, {newline: true}); | ||
}); | ||
}); | ||
return it('renders multiple line breaks', function(done) { | ||
var result, text; | ||
text = 'test\n\ntest\n'; | ||
result = 'test<br/><br/>test<br/>'; | ||
return test(text, result, done, { | ||
newline: true | ||
it('renders multiple line breaks', function (done) { | ||
const text = 'test\n\ntest\n'; | ||
const result = 'test<br/><br/>test<br/>'; | ||
return test(text, result, done, {newline: true}); | ||
}); | ||
}); | ||
}); | ||
return describe('with stream option enabled', function() { | ||
it('persists styles between toHtml() invocations', function(done) { | ||
var result, text; | ||
text = ['\x1b[31mred', 'also red']; | ||
result = '<span style="color:#A00">red</span><span style="color:' + '#A00">also red</span>'; | ||
return test(text, result, done, { | ||
stream: true | ||
describe('with stream option enabled', function () { | ||
it('persists styles between toHtml() invocations', function (done) { | ||
const text = ['\x1b[31mred', 'also red']; | ||
const result = '<span style="color:#A00">red</span><span style="color:#A00">also red</span>'; | ||
return test(text, result, done, {stream: true}); | ||
}); | ||
}); | ||
it('persists styles between more than two toHtml() invocations', function(done) { | ||
var result, text; | ||
text = ['\x1b[31mred', 'also red', 'and red']; | ||
result = '<span style="color:#A00">red</span><span style="color:' + '#A00">also red</span><span style="color:#A00">and red</span>'; | ||
return test(text, result, done, { | ||
stream: true | ||
it('persists styles between more than two toHtml() invocations', function (done) { | ||
const text = ['\x1b[31mred', 'also red', 'and red']; | ||
const result = '<span style="color:#A00">red</span><span style="color:#A00">also red</span><span style="color:#A00">and red</span>'; | ||
return test(text, result, done, {stream: true}); | ||
}); | ||
}); | ||
it('does not persist styles beyond their usefulness', function(done) { | ||
var result, text; | ||
text = ['\x1b[31mred', 'also red', '\x1b[30mblack', 'and black']; | ||
result = '<span style="color:#A00">red</span><span style="color:' + '#A00">also red</span><span style="color:#A00"><span style="color:' + '#000">black</span></span><span style="color:#000">and black</span>'; | ||
return test(text, result, done, { | ||
stream: true | ||
it('does not persist styles beyond their usefulness', function (done) { | ||
const text = ['\x1b[31mred', 'also red', '\x1b[30mblack', 'and black']; | ||
const result = '<span style="color:#A00">red</span><span style="color:#A00">also red</span><span style="color:#A00"><span style="color:#000">black</span></span><span style="color:#000">and black</span>'; | ||
return test(text, result, done, {stream: true}); | ||
}); | ||
}); | ||
return it('removes all state when encountering a reset', function(done) { | ||
var result, text; | ||
text = ['\x1b[1mthis is bold\x1b[0m, but this isn\'t', ' nor is this']; | ||
result = '<b>this is bold</b>, but this isn\'t nor is this'; | ||
return test(text, result, done, { | ||
stream: true | ||
it('removes one state when encountering a reset', function (done) { | ||
const text = ['\x1b[1mthis is bold\x1b[0m, but this isn\'t', ' nor is this']; | ||
const result = '<b>this is bold</b>, but this isn\'t nor is this'; | ||
return test(text, result, done, {stream: true}); | ||
}); | ||
}); | ||
it('removes multiple state when encountering a reset', function (done) { | ||
const text = ['\x1b[1mthis \x1b[9mis bold\x1b[0m, but this isn\'t', ' nor is this']; | ||
const result = '<b>this <strike>is bold</strike></b>, but this isn\'t nor is this'; | ||
return test(text, result, done, {stream: true}); | ||
}); | ||
}); | ||
}); | ||
}).call(this); | ||
describe('with custom colors enabled', function () { | ||
it('renders basic colors', function (done) { | ||
const text = ['\x1b[31mblue', 'not blue']; | ||
const result = '<span style="color:#00A">blue</span>not blue'; | ||
return test(text, result, done, {colors: {1: '#00A'}}); | ||
}); | ||
it('renders basic colors with streaming', function (done) { | ||
const text = ['\x1b[31mblue', 'also blue']; | ||
const result = '<span style="color:#00A">blue</span><span style="color:#00A">also blue</span>'; | ||
return test(text, result, done, {stream: true, colors: {1: '#00A'}}); | ||
}); | ||
it('renders custom colors and default colors', function (done) { | ||
const text = ['\x1b[31mblue', 'not blue', '\x1b[94mlight blue', 'not colored']; | ||
const result = '<span style="color:#00A">blue</span>not blue<span style="color:#55F">light blue</span>not colored'; | ||
return test(text, result, done, {colors: {1: '#00A'}}); | ||
}); | ||
it('renders custom colors and default colors together', function (done) { | ||
const text = ['\x1b[31mblue', 'not blue', '\x1b[94mlight blue', 'not colored']; | ||
const result = '<span style="color:#00A">blue</span>not blue<span style="color:#55F">light blue</span>not colored'; | ||
return test(text, result, done, {colors: {1: '#00A'}}); | ||
}); | ||
it('renders custom 8/ 16 colors', function (done) { | ||
// code - 90 + 8 = color | ||
// so 94 - 90 + 8 = 12 | ||
const text = ['\x1b[94mlighter blue']; | ||
const result = '<span style="color:#33F">lighter blue</span>'; | ||
return test(text, result, done, {colors: {12: '#33F'}}); | ||
}); | ||
it('renders custom 256 colors', function (done) { | ||
// code - 90 + 8 = color | ||
// so 94 - 90 + 8 = 12 | ||
const text = ['\x1b[38;5;125mdark red', 'then \x1b[38;5;126msome other color']; | ||
const result = '<span style="color:#af005f">dark red</span>then <span style="color:#af225f">some other color</span>'; | ||
return test(text, result, done, {colors: {126: '#af225f'}}); | ||
}); | ||
}); | ||
}); |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Shell access
Supply chain riskThis module accesses the system shell. Accessing the system shell increases the risk of executing arbitrary code.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
32424
3
12
774
91
2