jasmine-headless-webkit/js-lib/jsDump.js

210 lines
5.9 KiB
JavaScript
Raw Permalink Normal View History

/**
* jsDump
* Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com | http://flesler.blogspot.com
* Licensed under BSD (http://www.opensource.org/licenses/bsd-license.php)
* Date: 5/15/2008
* @projectDescription Advanced and extensible data dumping for Javascript.
* @version 1.0.0
* @author Ariel Flesler
* @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html}
*/
var jsDump;
(function(){
function quote( str ){
return '"' + str.toString().replace(/"/g, '\\"') + '"';
}
function literal( o ){
return o + '';
}
function join( pre, arr, post ){
var s = jsDump.separator(),
base = jsDump.indent(),
inner = jsDump.indent(1);
if( arr.join )
arr = arr.join( ',' + s + inner );
if( !arr )
return pre + post;
return [ pre, inner + arr, base + post ].join(s);
}
function array( arr ){
var i = arr.length, ret = Array(i);
this.up();
while( i-- )
ret[i] = this.parse( arr[i] );
this.down();
return join( '[', ret, ']' );
}
var reName = /^function (\w+)/;
jsDump = {
2011-09-09 19:35:51 +00:00
doParse:function(obj) {
this.alreadySeenObjects = [];
return this.parse(obj);
},
parse:function( obj, type ){//type is used mostly internally, you can fix a (custom)type in advance
var parser = this.parsers[ type || this.typeOf(obj) ];
type = typeof parser;
return type == 'function' ? parser.call( this, obj ) :
type == 'string' ? parser :
this.parsers.error;
},
typeOf:function( obj ){
var type = typeof obj,
kind;
if ( type == 'object' || type == 'function' ) {
if ( obj === null )
return 'null';
// Extract Staff from [Object Staff]
kind = Object.prototype.toString.call(obj).slice(8, -1);
switch ( kind ) {
case 'Array':
return 'array';
case 'Date':
return 'date';
case 'RegExp':
return 'regexp';
case 'Window': //Firefox, IE, Opera
case 'DOMWindow': //WebKit
case 'global':
return 'window';
case 'HTMLDocument': //WebKit, Firefox, Opera
case 'Document': // IE
return 'document';
case 'NodeList':
return 'nodelist';
default:
if ( 'callee' in obj )
// Opera: Object.prototype.toString.call(arguments) == 'Object' :(
return 'arguments';
else if ( 'ownerDocument' in obj && 'defaultView' in obj.ownerDocument && obj instanceof obj.ownerDocument.defaultView.Node )
return 'node';
}
}
return type;
},
separator:function(){
return this.multiline ? this.HTML ? '<br />' : '\n' : this.HTML ? '&nbsp;' : ' ';
},
indent:function( extra ){// extra can be a number, shortcut for increasing-calling-decreasing
if( !this.multiline )
return '';
var chr = this.indentChar;
if( this.HTML )
chr = chr.replace(/\t/g,' ').replace(/ /g,'&nbsp;');
return Array( this._depth_ + (extra||0) ).join(chr);
},
up:function( a ){
this._depth_ += a || 1;
},
down:function( a ){
this._depth_ -= a || 1;
},
setParser:function( name, parser ){
this.parsers[name] = parser;
},
// The next 3 are exposed so you can use them
quote:quote,
literal:literal,
join:join,
_depth_: 1,
// This is the list of parsers, to modify them, use jsDump.setParser
parsers:{
window: '[Window]',
document: '[Document]',
error:'[ERROR]', //when no parser is found, shouldn't happen
unknown: '[Unknown]',
'null':'null',
undefined:'undefined',
'function':function( fn ){
var ret = 'function',
name = 'name' in fn ? fn.name : (reName.exec(fn)||[])[1];//functions never have name in IE
if( name )
ret += ' ' + name;
ret += '(';
ret = [ ret, this.parse( fn, 'functionArgs' ), '){'].join('');
return join( ret, this.parse(fn,'functionCode'), '}' );
},
array: array,
nodelist: array,
arguments: array,
object:function( map ){
var ret = [ ];
this.up();
var keys = [];
for (var key in map) { keys.push(key); }
keys = keys.sort();
for( var i = 0; i < keys.length; ++i ) {
var key = keys[i];
if (!this.ignoreFunctions || this.typeOf(map[key]) != 'function') {
var value = "<< LOOP >>";
2011-09-09 19:35:51 +00:00
if ((typeof map[key] != 'object') || this.alreadySeenObjects.indexOf(map[key]) == -1) {
this.alreadySeenObjects.push(map[key]);
value = this.parse(map[key]);
}
ret.push( this.parse(key,'key') + ': ' + value );
}
}
this.down();
return join( '{', ret, '}' );
},
node:function( node ){
var open = this.HTML ? '&lt;' : '<',
close = this.HTML ? '&gt;' : '>';
var tag = node.nodeName.toLowerCase(),
ret = open + tag;
for( var a in this.DOMAttrs ){
var val = node[this.DOMAttrs[a]];
if( val )
ret += ' ' + a + '=' + this.parse( val, 'attribute' );
}
return ret + close + open + '/' + tag + close;
},
functionArgs:function( fn ){//function calls it internally, it's the arguments part of the function
var l = fn.length;
if( !l ) return '';
var args = Array(l);
while( l-- )
args[l] = String.fromCharCode(97+l);//97 is 'a'
return ' ' + args.join(', ') + ' ';
},
key:quote, //object calls it internally, the key part of an item in a map
functionCode:'[code]', //function calls it internally, it's the content of the function
attribute:quote, //node calls it internally, it's an html attribute value
string:quote,
date:quote,
regexp:literal, //regex
number:literal,
'boolean':literal
},
DOMAttrs:{//attributes to dump from nodes, name=>realName
id:'id',
name:'name',
'class':'className'
},
alreadySeenObjects:[],
ignoreFunctions:true,
HTML:false,//if true, entities are escaped ( <, >, \t, space and \n )
indentChar:' ',//indentation unit
multiline:true //if true, items in a collection, are separated by a \n, else just a space.
};
})();
if (typeof exports !== 'undefined') {
module.exports = jsDump;
}