2011-09-08 15:48:33 +00:00
|
|
|
/**
|
|
|
|
* 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);
|
|
|
|
},
|
2011-09-08 15:48:33 +00:00
|
|
|
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 ? ' ' : ' ';
|
|
|
|
},
|
|
|
|
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,' ');
|
|
|
|
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) {
|
2011-09-08 15:48:33 +00:00
|
|
|
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 ? '<' : '<',
|
|
|
|
close = this.HTML ? '>' : '>';
|
|
|
|
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;
|
|
|
|
}
|