forked from travis-ci/travis-ci
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Sven Fuchs
committed
Jul 4, 2011
1 parent
1c4871a
commit a88e446
Showing
2 changed files
with
165 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
var Deansi = { | ||
styles: { | ||
'0': null, | ||
'1': 'bold', | ||
'4': 'underscore', | ||
'30': 'black', | ||
'31': 'red', | ||
'32': 'green', | ||
'33': 'yellow', | ||
'34': 'blue', | ||
'35': 'magenta', | ||
'36': 'cyan', | ||
'37': 'white', | ||
'40': 'bg-black', | ||
'41': 'bg-red', | ||
'42': 'bg-green', | ||
'43': 'bg-yellow', | ||
'44': 'bg-blue', | ||
'45': 'bg-magenta', | ||
'46': 'bg-cyan', | ||
'47': 'bg-white', | ||
}, | ||
parse: function(string) { | ||
string = this.replace_escapes(string); | ||
string = this.replace_styles(string); | ||
string = this.remove_closings(string); | ||
string = this.parse_linefeeds(string); | ||
return string; | ||
}, | ||
replace_escapes: function(string) { | ||
return string.replace(String.fromCharCode(27), ''); | ||
}, | ||
replace_styles: function(string) { | ||
var pattern = /\[(?:0;)?((?:1|4|30|31|32|33|34|35|36|37|40|41|42|43|44|45|46|47|;)+)m(.*?)(?=(\[(?:[\d;]?m\(B)?)|$)/gm; | ||
return string.replace(pattern, function(match, styles, string) { | ||
return '<span class="' + Deansi.to_styles(styles) + '">' + string + '</span>'; | ||
}); | ||
}, | ||
remove_closings: function(string) { | ||
return string.replace(/\[0?m(?:\(B)?/gm, ''); | ||
}, | ||
parse_linefeeds: function(string) { | ||
string = string.replace(/\[K\r/, "\r"); | ||
string = string.replace(/^.*\r(?!$)/gm, ''); | ||
return string; | ||
}, | ||
to_styles: function(string) { | ||
return _.compact(_.map(string.split(';'), function(number) { return Deansi.styles[number]; })).join(' '); | ||
}, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
String.prototype.repeat = function(num) { | ||
return new Array(num + 1).join(this); | ||
} | ||
|
||
describe('Deansi', function() { | ||
function deansi(string) { | ||
return Deansi.parse(string); | ||
}; | ||
|
||
describe('colors', function() { | ||
var sets = [ | ||
{ ansi: "[30m", class: 'black' }, | ||
{ ansi: "[31m", class: 'red' }, | ||
{ ansi: "[32m", class: 'green' }, | ||
{ ansi: "[33m", class: 'yellow' }, | ||
{ ansi: "[34m", class: 'blue' }, | ||
{ ansi: "[35m", class: 'magenta' }, | ||
{ ansi: "[36m", class: 'cyan' }, | ||
{ ansi: "[37m", class: 'white' }, | ||
{ ansi: "[30;1m", class: 'black bold' }, | ||
{ ansi: "[31;1m", class: 'red bold' }, | ||
{ ansi: "[32;1m", class: 'green bold' }, | ||
{ ansi: "[34;1m", class: 'blue bold' }, | ||
{ ansi: "[33;1m", class: 'yellow bold' }, | ||
{ ansi: "[35;1m", class: 'magenta bold' }, | ||
{ ansi: "[36;1m", class: 'cyan bold' }, | ||
{ ansi: "[37;1m", class: 'white bold' }, | ||
{ ansi: "[42;37;1m", class: 'bg-green white bold' }, | ||
]; | ||
|
||
it('replaces ANSI escape sequences having no closing sequence with a span having the respective css classes', function() { | ||
for(ix in sets) { | ||
var set = sets[ix]; | ||
source = (set.ansi + 'FOO').repeat(3); | ||
expected = ('<span class="' + set.class +'">FOO</span>').repeat(3); | ||
expect(deansi(source)).toEqual(expected); | ||
} | ||
}); | ||
|
||
it('replaces ANSI escape sequences having a closing sequence [m with a span having the respective css classes', function() { | ||
for(ix in sets) { | ||
var set = sets[ix]; | ||
source = (set.ansi + 'FOO[m').repeat(3); | ||
expected = ('<span class="' + set.class +'">FOO</span>').repeat(3); | ||
expect(deansi(source)).toEqual(expected); | ||
} | ||
}); | ||
|
||
it('replaces ANSI escape sequences having a closing sequence [0m with a span having the respective css classes', function() { | ||
for(ix in sets) { | ||
var set = sets[ix]; | ||
source = (set.ansi + 'FOO[0m').repeat(3); | ||
expected = ('<span class="' + set.class +'">FOO</span>').repeat(3); | ||
expect(deansi(source)).toEqual(expected); | ||
} | ||
}); | ||
|
||
// not sure where this comes from. can't find it in http://ascii-table.com/ansi-escape-sequences.php | ||
it('replaces ANSI escape sequences having a closing sequence [m(B with a span having the respective css classes', function() { | ||
for(ix in sets) { | ||
var set = sets[ix]; | ||
source = (set.ansi + 'FOO[m(B').repeat(3); | ||
expected = ('<span class="' + set.class +'">FOO</span>').repeat(3); | ||
expect(deansi(source)).toEqual(expected); | ||
} | ||
}); | ||
|
||
it('replaces ANSI escape sequence (real examples)', function() { | ||
var examples = [ | ||
{ source: '[42;37;1mPassed[0m', result: '<span class="bg-green white bold">Passed</span>' }, | ||
{ source: '[0;33;40mFailure', result: '<span class="yellow bg-black">Failure</span>' }, | ||
{ source: '[0;37;40mSuccess', result: '<span class="white bg-black">Success</span>' }, | ||
{ source: '[32m.[0m[31mF[0m', result: '<span class="green">.</span><span class="red">F</span>' }, | ||
{ source: '[31m2 failed[0m, [33m2 undefined[0m, [32m35 passed[0m', result: '<span class="red">2 failed</span>, <span class="yellow">2 undefined</span>, <span class="green">35 passed</span>' }, | ||
{ source: '[31m2 failed[0m, [36m1 skipped[0m, [33m7 undefined[0m, [32m212 passed[0m', result: '<span class="red">2 failed</span>, <span class="cyan">1 skipped</span>, <span class="yellow">7 undefined</span>, <span class="green">212 passed</span>' } | ||
] | ||
for(ix in examples) { | ||
var example = examples[ix]; | ||
expect(deansi(example.source)).toEqual(example.result); | ||
} | ||
}); | ||
}); | ||
|
||
describe('carriage returns', function() { | ||
it('replaces a line followed by a carriage return', function() { | ||
source = 'remote: Compressing objects: 100% (21/21) \rremote: Compressing objects: 100% (21/21), done.'; | ||
expected = 'remote: Compressing objects: 100% (21/21), done.'; | ||
expect(deansi(source)).toEqual(expected); | ||
}); | ||
|
||
it('replaces a line followed by an ansii clear line escape sequence and a carriage return', function() { | ||
source = 'remote: Compressing objects: 100% (21/21) [K\rremote: Compressing objects: 100% (21/21), done.'; | ||
expected = 'remote: Compressing objects: 100% (21/21), done.'; | ||
expect(deansi(source)).toEqual(expected); | ||
}); | ||
|
||
it('removes [K sequences preceeding a carriage return', function() { | ||
source = 'remote: Compressing objects: 100% (21/21), done. [K\r'; | ||
expected = 'remote: Compressing objects: 100% (21/21), done. \r'; | ||
expect(deansi(source)).toEqual(expected); | ||
}); | ||
|
||
it('does not replaces a line followed by a carriage return when this is the last character in the string', function() { | ||
source = 'remote: Compressing objects: 100% (21/21) \r'; | ||
expected = 'remote: Compressing objects: 100% (21/21) \r'; | ||
expect(deansi(source)).toEqual(expected); | ||
}); | ||
|
||
it('does not replace a line followed by a carriage return and a newline', function() { | ||
source = 'remote: Counting objects: 31, done.\r\nremote: Compressing objects: 100% (21/21), done.'; | ||
expected = 'remote: Counting objects: 31, done.\r\nremote: Compressing objects: 100% (21/21), done.'; | ||
expect(deansi(source)).toEqual(expected); | ||
}); | ||
}); | ||
}); |