|
|
@ -21,9 +21,99 @@ exports.error = function (x) { |
|
|
|
* in the best way possible given the different types. |
|
|
|
* |
|
|
|
* @param {Object} value The object to print out |
|
|
|
* @param {Boolean} showHidden Flag that shows hidden (not enumerable) properties of objects. |
|
|
|
*/ |
|
|
|
exports.inspect = function (value) { |
|
|
|
return formatter(value, '', []); |
|
|
|
exports.inspect = function (obj, showHidden) { |
|
|
|
var seen = []; |
|
|
|
function format(value) { |
|
|
|
var keys, visible_keys, base, type, braces; |
|
|
|
// Primitive types cannot have properties
|
|
|
|
switch (typeof value) { |
|
|
|
case 'undefined': return 'undefined'; |
|
|
|
case 'string': return JSON.stringify(value); |
|
|
|
case 'number': return '' + value; |
|
|
|
case 'boolean': return '' + value; |
|
|
|
} |
|
|
|
// For some reason typeof null is "object", so special case here.
|
|
|
|
if (value === null) { |
|
|
|
return 'null'; |
|
|
|
} |
|
|
|
|
|
|
|
// Look up the keys of the object.
|
|
|
|
keys = showHidden ? Object.getOwnPropertyNames(value).map(function (key) { |
|
|
|
return '' + key; |
|
|
|
}) : Object.keys(value); |
|
|
|
visible_keys = Object.keys(value); |
|
|
|
|
|
|
|
// Functions without properties can be shortcutted.
|
|
|
|
if (typeof value === 'function' && keys.length === 0) { |
|
|
|
if (value instanceof RegExp) { |
|
|
|
return '' + value; |
|
|
|
} else { |
|
|
|
return '[Function]'; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// Determine the object type
|
|
|
|
if (value instanceof Array) { |
|
|
|
type = 'Array'; |
|
|
|
braces = ["[", "]"]; |
|
|
|
} else { |
|
|
|
type = 'Object'; |
|
|
|
braces = ["{", "}"]; |
|
|
|
} |
|
|
|
|
|
|
|
// Make functions say that they are functions
|
|
|
|
if (typeof value === 'function') { |
|
|
|
base = (value instanceof RegExp) ? ' ' + value : ' [Function]'; |
|
|
|
} else { |
|
|
|
base = ""; |
|
|
|
} |
|
|
|
|
|
|
|
seen.push(value); |
|
|
|
|
|
|
|
if (keys.length === 0) { |
|
|
|
return braces[0] + base + braces[1]; |
|
|
|
} |
|
|
|
|
|
|
|
return braces[0] + base + "\n" + (keys.map(function (key) { |
|
|
|
var name, str; |
|
|
|
if (value.__lookupGetter__) { |
|
|
|
if (value.__lookupGetter__(key)) { |
|
|
|
if (value.__lookupSetter__(key)) { |
|
|
|
str = "[Getter/Setter]"; |
|
|
|
} else { |
|
|
|
str = "[Getter]"; |
|
|
|
} |
|
|
|
} else { |
|
|
|
if (value.__lookupSetter__(key)) { |
|
|
|
str = "[Setter]"; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
if (visible_keys.indexOf(key) < 0) { |
|
|
|
name = "[" + key + "]"; |
|
|
|
} |
|
|
|
if (!str) { |
|
|
|
if (seen.indexOf(value[key]) < 0) { |
|
|
|
str = format(value[key]); |
|
|
|
} else { |
|
|
|
str = '[Circular]'; |
|
|
|
} |
|
|
|
} |
|
|
|
if (typeof name === 'undefined') { |
|
|
|
if (type === 'Array' && key.match(/^\d+$/)) { |
|
|
|
return str; |
|
|
|
} |
|
|
|
name = JSON.stringify('' + key); |
|
|
|
} |
|
|
|
|
|
|
|
return name + ": " + str; |
|
|
|
}).join(",\n")).split("\n").map(function (line) { |
|
|
|
return ' ' + line; |
|
|
|
}).join('\n') + "\n" + braces[1]; |
|
|
|
} |
|
|
|
return format(obj); |
|
|
|
}; |
|
|
|
|
|
|
|
exports.p = function (x) { |
|
|
@ -70,76 +160,4 @@ exports.exec = function (command) { |
|
|
|
*/ |
|
|
|
exports.inherits = process.inherits; |
|
|
|
|
|
|
|
/** |
|
|
|
* A recursive function to format an object - used by inspect. |
|
|
|
* |
|
|
|
* @param {Object} value |
|
|
|
* the value to format |
|
|
|
* @param {String} indent |
|
|
|
* the indent level of any nested objects, since they are formatted over |
|
|
|
* more than one line |
|
|
|
* @param {Array} parents |
|
|
|
* contains all objects above the current one in the heirachy, used to |
|
|
|
* prevent getting stuck in a loop on circular references |
|
|
|
*/ |
|
|
|
var formatter = function(value, indent, parents) { |
|
|
|
switch(typeof(value)) { |
|
|
|
case 'string': return JSON.stringify(value); |
|
|
|
case 'number': return '' + value; |
|
|
|
case 'function': return '[Function]'; |
|
|
|
case 'boolean': return '' + value; |
|
|
|
case 'undefined': return 'undefined'; |
|
|
|
case 'object': |
|
|
|
if (value == null) return 'null'; |
|
|
|
if (parents.indexOf(value) >= 0) return '[Circular]'; |
|
|
|
parents.push(value); |
|
|
|
|
|
|
|
if (value instanceof Array && Object.keys(value).length === value.length) { |
|
|
|
return formatObject(value, indent, parents, '[]', function(x, f) { |
|
|
|
return f(value[x]); |
|
|
|
}); |
|
|
|
} else { |
|
|
|
return formatObject(value, indent, parents, '{}', function(x, f) { |
|
|
|
var child; |
|
|
|
if (value.__lookupGetter__(x)) { |
|
|
|
if (value.__lookupSetter__(x)) { |
|
|
|
child = "[Getter/Setter]"; |
|
|
|
} else { |
|
|
|
child = "[Getter]"; |
|
|
|
} |
|
|
|
} else { |
|
|
|
if (value.__lookupSetter__(x)) { |
|
|
|
child = "[Setter]"; |
|
|
|
} else { |
|
|
|
child = f(value[x]); |
|
|
|
} |
|
|
|
} |
|
|
|
return f(x) + ': ' + child; |
|
|
|
}); |
|
|
|
} |
|
|
|
return buffer; |
|
|
|
default: |
|
|
|
throw('inspect unimplemented for ' + typeof(value)); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Helper function for formatting either an array or an object, used internally by formatter |
|
|
|
*/ |
|
|
|
var formatObject = function(obj, indent, parents, parenthesis, entryFormatter) { |
|
|
|
var buffer = parenthesis[0]; |
|
|
|
var values = []; |
|
|
|
var x; |
|
|
|
|
|
|
|
var localFormatter = function(value) { |
|
|
|
return formatter(value, indent + ' ', parents); |
|
|
|
}; |
|
|
|
for (x in obj) { |
|
|
|
values.push(indent + ' ' + entryFormatter(x, localFormatter)); |
|
|
|
} |
|
|
|
if (values.length > 0) { |
|
|
|
buffer += "\n" + values.join(",\n") + "\n" + indent; |
|
|
|
} |
|
|
|
buffer += parenthesis[1]; |
|
|
|
return buffer; |
|
|
|
} |
|
|
|
// Object.create(null, {name: {value: "Tim", enumerable: true}})
|