-
-
Notifications
You must be signed in to change notification settings - Fork 36
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Printing the constructor name for non-plain objects #15
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -15,6 +15,7 @@ var objectToString = Object.prototype.toString; | |
var functionToString = Function.prototype.toString; | ||
var match = String.prototype.match; | ||
var bigIntValueOf = typeof BigInt === 'function' ? BigInt.prototype.valueOf : null; | ||
var getPrototype = Object.getPrototypeOf || function(o) { return o.__proto__; }; | ||
|
||
var inspectCustom = require('./util.inspect').custom; | ||
var inspectSymbol = inspectCustom && isSymbol(inspectCustom) ? inspectCustom : null; | ||
|
@@ -145,9 +146,12 @@ module.exports = function inspect_(obj, options, depth, seen) { | |
return markBoxed(inspect(String(obj))); | ||
} | ||
if (!isDate(obj) && !isRegExp(obj)) { | ||
var typeString = getTypeString(obj); | ||
var prefix = typeString ? typeString + ' ' : ''; | ||
var xs = arrObjKeys(obj, inspect); | ||
if (xs.length === 0) { return '{}'; } | ||
return '{ ' + xs.join(', ') + ' }'; | ||
return xs.length === 0 | ||
? prefix + '{}' | ||
: prefix + '{ ' + xs.join(', ') + ' }'; | ||
} | ||
return String(obj); | ||
}; | ||
|
@@ -319,3 +323,34 @@ function arrObjKeys(obj, inspect) { | |
} | ||
return xs; | ||
} | ||
|
||
// Returns the object's constructor name or null if it is a plain object | ||
// or doesn't have a prototype. | ||
function getTypeString(o) { | ||
if (Object.prototype.toString.call(o) !== '[object Object]') return null; | ||
var prototype = getPrototype(o); | ||
if (!prototype) return null; | ||
|
||
var constructorName = o.constructor ? o.constructor.name : null; | ||
var isPlainObject = constructorName === 'Object' && looksLikeObjectPrototype(prototype); | ||
if (isPlainObject) { | ||
return null; | ||
} | ||
|
||
return constructorName; | ||
} | ||
|
||
// Indicates whether the specified object appears to be Object.prototype, | ||
// regardless of the object's realm. | ||
function looksLikeObjectPrototype(o) { | ||
if (o === Object.prototype) return true; | ||
|
||
// Cross-realm objects use a different Object, so we have to use a heuristic. | ||
return !getPrototype(o) | ||
&& o.hasOwnProperty('hasOwnProperty') | ||
&& o.hasOwnProperty('isPrototypeOf') | ||
&& o.hasOwnProperty('propertyIsEnumerable') | ||
&& o.hasOwnProperty('toLocaleString') | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. should these check that they're functions, and ideally, that they behave as expected? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think there's anything to be gained by that. Consider that you have an object with own properties What's the worst that can happen? The worst case is that you have an object that's trying hard to look like a plain object, and that your library prints it just like a plain object. I don't think that's bad. After all, this library isn't generating structured information. It's generating a debug string that is supposed to help a developer understand an object graph. And I don't think that anybody will complain if something that's virtually indistinguishable from a plain object is visualized as a plain object. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's a fair point. However, to be indistinguishable, this library would have to be unable to distinguish it. One extreme length we could go to is ensuring not just that they're all functions, but also that |
||
&& o.hasOwnProperty('toString') | ||
&& o.hasOwnProperty('valueOf'); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
var inspect = require('../'); | ||
var test = require('tape'); | ||
|
||
test('prototype is Object.prototype', function (t) { | ||
t.plan(1); | ||
var obj = {}; | ||
t.equal(inspect(obj), '{}'); | ||
}); | ||
|
||
test('prototype is null', function (t) { | ||
t.plan(1); | ||
var obj = Object.create(null); | ||
t.equal(inspect(obj), '{}'); | ||
}); | ||
|
||
test('prototype from new', function (t) { | ||
t.plan(1); | ||
function Foo() {} | ||
var obj = new Foo(); | ||
t.equal(inspect(obj), 'Foo {}'); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about the older engines where
__proto__
isn't even available?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In that case,
__proto__
will beundefined
, as will be the result ofgetPrototype
. Consequently,getTypeString
will return null (because the result ofgetPrototype
is falsey). And the code will behave as it always has, not printing a type prefix.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wouldn't a
{ __proto__: 3 }
return3
in an engine where it's not available?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That will happen even in engines that support
__proto__
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ExE-Boss that spec text only treats it as a normal data property when it's not a string, or computed.
({ __proto__: 3 }).__proto__ === Object.prototype
returnstrue
in a modern engine, but in, say, IE 8, it returnsfalse
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Specifically, in IE 8,
({ __proto__: 3 }).__proto__
returns3
.