Browse Source

util: Divide inspect() into some subroutines

koichik 13 years ago
parent
commit
98b64422bb
  1. 398
      lib/util.js

398
lib/util.js

@ -95,227 +95,249 @@ var error = exports.error = function(x) {
* output. Default is false (no coloring). * output. Default is false (no coloring).
*/ */
function inspect(obj, showHidden, depth, colors) { function inspect(obj, showHidden, depth, colors) {
var seen = []; var ctx = {
showHidden: showHidden,
var stylize = function(str, styleType) { seen: [],
// http://en.wikipedia.org/wiki/ANSI_escape_code#graphics stylize: colors ? stylizeWithColor : stylizeNoColor,
var styles =
{ 'bold' : [1, 22],
'italic' : [3, 23],
'underline' : [4, 24],
'inverse' : [7, 27],
'white' : [37, 39],
'grey' : [90, 39],
'black' : [30, 39],
'blue' : [34, 39],
'cyan' : [36, 39],
'green' : [32, 39],
'magenta' : [35, 39],
'red' : [31, 39],
'yellow' : [33, 39] };
var style =
{ 'special': 'cyan',
'number': 'blue',
'boolean': 'yellow',
'undefined': 'grey',
'null': 'bold',
'string': 'green',
'date': 'magenta',
// "name": intentionally not styling
'regexp': 'red' }[styleType];
if (style) {
return '\033[' + styles[style][0] + 'm' + str +
'\033[' + styles[style][1] + 'm';
} else {
return str;
}
}; };
if (! colors) { return formatValue(ctx, obj, (typeof depth === 'undefined' ? 2 : depth));
stylize = function(str, styleType) { return str; }; }
} exports.inspect = inspect;
function format(value, recurseTimes) {
// Provide a hook for user-specified inspect functions.
// Check that value is an object with an inspect function on it
if (value && typeof value.inspect === 'function' &&
// Filter out the util module, it's inspect function is special
value !== exports &&
// Also filter out any prototype objects using the circular check.
!(value.constructor && value.constructor.prototype === value)) {
return value.inspect(recurseTimes);
}
// Primitive types cannot have properties // http://en.wikipedia.org/wiki/ANSI_escape_code#graphics
switch (typeof value) { var colors = {
case 'undefined': 'bold' : [1, 22],
return stylize('undefined', 'undefined'); 'italic' : [3, 23],
'underline' : [4, 24],
'inverse' : [7, 27],
'white' : [37, 39],
'grey' : [90, 39],
'black' : [30, 39],
'blue' : [34, 39],
'cyan' : [36, 39],
'green' : [32, 39],
'magenta' : [35, 39],
'red' : [31, 39],
'yellow' : [33, 39]
};
case 'string': var styles = {
var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '') 'special': 'cyan',
.replace(/'/g, "\\'") 'number': 'blue',
.replace(/\\"/g, '"') + '\''; 'boolean': 'yellow',
return stylize(simple, 'string'); 'undefined': 'grey',
'null': 'bold',
'string': 'green',
'date': 'magenta',
// "name": intentionally not styling
'regexp': 'red'
};
case 'number':
return stylize('' + value, 'number');
case 'boolean': function stylizeWithColor(str, styleType) {
return stylize('' + value, 'boolean'); var style = styles[styleType];
}
// For some reason typeof null is "object", so special case here.
if (value === null) {
return stylize('null', 'null');
}
// Look up the keys of the object. if (style) {
var visible_keys = Object.keys(value); return '\033[' + colors[style][0] + 'm' + str +
var keys = showHidden ? Object.getOwnPropertyNames(value) : visible_keys; '\033[' + colors[style][1] + 'm';
} else {
return str;
}
}
// Functions without properties can be shortcutted.
if (typeof value === 'function' && keys.length === 0) {
var name = value.name ? ': ' + value.name : '';
return stylize('[Function' + name + ']', 'special');
}
// RegExp without properties can be shortcutted function stylizeNoColor(str, styleType) {
if (isRegExp(value) && keys.length === 0) { return str;
return stylize('' + value, 'regexp'); }
}
// Dates without properties can be shortcutted
if (isDate(value) && keys.length === 0) {
return stylize(value.toUTCString(), 'date');
}
var base, type, braces; function formatValue(ctx, value, recurseTimes) {
// Determine the object type // Provide a hook for user-specified inspect functions.
if (isArray(value)) { // Check that value is an object with an inspect function on it
type = 'Array'; if (value && typeof value.inspect === 'function' &&
braces = ['[', ']']; // Filter out the util module, it's inspect function is special
} else { value !== exports &&
type = 'Object'; // Also filter out any prototype objects using the circular check.
braces = ['{', '}']; !(value.constructor && value.constructor.prototype === value)) {
} return value.inspect(recurseTimes);
}
// Make functions say that they are functions // Primitive types cannot have properties
var primitive = formatPrimitive(ctx, value);
if (primitive) {
return primitive;
}
// Look up the keys of the object.
var visibleKeys = Object.keys(value);
var keys = ctx.showHidden ? Object.getOwnPropertyNames(value) : visibleKeys;
// Some type of object without properties can be shortcutted.
if (keys.length === 0) {
if (typeof value === 'function') { if (typeof value === 'function') {
var n = value.name ? ': ' + value.name : ''; var name = value.name ? ': ' + value.name : '';
base = ' [Function' + n + ']'; return ctx.stylize('[Function' + name + ']', 'special');
} else {
base = '';
} }
// Make RegExps say that they are RegExps
if (isRegExp(value)) { if (isRegExp(value)) {
base = ' ' + value; return ctx.stylize('' + value, 'regexp');
} }
// Make dates with properties first say the date
if (isDate(value)) { if (isDate(value)) {
base = ' ' + value.toUTCString(); return ctx.stylize(value.toUTCString(), 'date');
} }
}
if (keys.length === 0) { var base = '', array = false, braces = ['{', '}'];
return braces[0] + base + braces[1];
}
if (recurseTimes < 0) { // Make Array say that they are Array
if (isRegExp(value)) { if (isArray(value)) {
return stylize('' + value, 'regexp'); array = true;
} else { braces = ['[', ']'];
return stylize('[Object]', 'special'); }
}
// Make functions say that they are functions
if (typeof value === 'function') {
var n = value.name ? ': ' + value.name : '';
base = ' [Function' + n + ']';
}
// Make RegExps say that they are RegExps
if (isRegExp(value)) {
base = ' ' + value;
}
// Make dates with properties first say the date
if (isDate(value)) {
base = ' ' + value.toUTCString();
}
if (keys.length === 0) {
return braces[0] + base + braces[1];
}
if (recurseTimes < 0) {
if (isRegExp(value)) {
return ctx.stylize('' + value, 'regexp');
} else {
return ctx.stylize('[Object]', 'special');
} }
}
seen.push(value); ctx.seen.push(value);
var output = keys.map(function(key) { var output = keys.map(function(key) {
var name, str; return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array);
if (value.__lookupGetter__) { });
if (value.__lookupGetter__(key)) {
if (value.__lookupSetter__(key)) { ctx.seen.pop();
str = stylize('[Getter/Setter]', 'special');
} else { return reduceToSingleString(output, base, braces);
str = stylize('[Getter]', 'special'); }
}
} else {
if (value.__lookupSetter__(key)) { function formatPrimitive(ctx, value) {
str = stylize('[Setter]', 'special'); switch (typeof value) {
} case 'undefined':
} return ctx.stylize('undefined', 'undefined');
case 'string':
var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '')
.replace(/'/g, "\\'")
.replace(/\\"/g, '"') + '\'';
return ctx.stylize(simple, 'string');
case 'number':
return ctx.stylize('' + value, 'number');
case 'boolean':
return ctx.stylize('' + value, 'boolean');
}
// For some reason typeof null is "object", so special case here.
if (value === null) {
return ctx.stylize('null', 'null');
}
}
function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) {
var name, str;
if (value.__lookupGetter__) {
if (value.__lookupGetter__(key)) {
if (value.__lookupSetter__(key)) {
str = ctx.stylize('[Getter/Setter]', 'special');
} else {
str = ctx.stylize('[Getter]', 'special');
} }
if (visible_keys.indexOf(key) < 0) { } else {
name = '[' + key + ']'; if (value.__lookupSetter__(key)) {
str = ctx.stylize('[Setter]', 'special');
} }
if (!str) { }
if (seen.indexOf(value[key]) < 0) { }
if (recurseTimes === null) { if (visibleKeys.indexOf(key) < 0) {
str = format(value[key]); name = '[' + key + ']';
} else { }
str = format(value[key], recurseTimes - 1); if (!str) {
} if (ctx.seen.indexOf(value[key]) < 0) {
if (str.indexOf('\n') > -1) { if (recurseTimes === null) {
if (isArray(value)) { str = formatValue(ctx, value[key], null);
str = str.split('\n').map(function(line) { } else {
return ' ' + line; str = formatValue(ctx, value[key], recurseTimes - 1);
}).join('\n').substr(2);
} else {
str = '\n' + str.split('\n').map(function(line) {
return ' ' + line;
}).join('\n');
}
}
} else {
str = stylize('[Circular]', 'special');
}
} }
if (typeof name === 'undefined') { if (str.indexOf('\n') > -1) {
if (type === 'Array' && key.match(/^\d+$/)) { if (array) {
return str; str = str.split('\n').map(function(line) {
} return ' ' + line;
name = JSON.stringify('' + key); }).join('\n').substr(2);
if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) {
name = name.substr(1, name.length - 2);
name = stylize(name, 'name');
} else { } else {
name = name.replace(/'/g, "\\'") str = '\n' + str.split('\n').map(function(line) {
.replace(/\\"/g, '"') return ' ' + line;
.replace(/(^"|"$)/g, "'"); }).join('\n');
name = stylize(name, 'string');
} }
} }
return name + ': ' + str;
});
seen.pop();
var numLinesEst = 0;
var length = output.reduce(function(prev, cur) {
numLinesEst++;
if (cur.indexOf('\n') >= 0) numLinesEst++;
return prev + cur.length + 1;
}, 0);
if (length > (require('readline').columns || 50)) {
output = braces[0] +
(base === '' ? '' : base + '\n ') +
' ' +
output.join(',\n ') +
' ' +
braces[1];
} else { } else {
output = braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1]; str = ctx.stylize('[Circular]', 'special');
} }
}
if (typeof name === 'undefined') {
if (array && key.match(/^\d+$/)) {
return str;
}
name = JSON.stringify('' + key);
if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) {
name = name.substr(1, name.length - 2);
name = ctx.stylize(name, 'name');
} else {
name = name.replace(/'/g, "\\'")
.replace(/\\"/g, '"')
.replace(/(^"|"$)/g, "'");
name = ctx.stylize(name, 'string');
}
}
return output; return name + ': ' + str;
}
function reduceToSingleString(output, base, braces) {
var numLinesEst = 0;
var length = output.reduce(function(prev, cur) {
numLinesEst++;
if (cur.indexOf('\n') >= 0) numLinesEst++;
return prev + cur.length + 1;
}, 0);
if (length > (require('readline').columns || 50)) {
return braces[0] +
(base === '' ? '' : base + '\n ') +
' ' +
output.join(',\n ') +
' ' +
braces[1];
} }
return format(obj, (typeof depth === 'undefined' ? 2 : depth));
return braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1];
} }
exports.inspect = inspect;
function isArray(ar) { function isArray(ar) {

Loading…
Cancel
Save