Skip to content

Commit 799b58f

Browse files
committed
[New] respect Symbol.toStringTag on objects
1 parent 33bdee9 commit 799b58f

File tree

2 files changed

+57
-3
lines changed

2 files changed

+57
-3
lines changed

index.js

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,17 @@ var gOPS = Object.getOwnPropertySymbols;
1919
var symToString = typeof Symbol === 'function' ? Symbol.prototype.toString : null;
2020
var isEnumerable = Object.prototype.propertyIsEnumerable;
2121

22+
var gPO = (typeof Reflect === 'function' ? Reflect.getPrototypeOf : Object.getPrototypeOf) || (
23+
[].__proto__ === Array.prototype // eslint-disable-line no-proto
24+
? function (O) {
25+
return O.__proto__; // eslint-disable-line no-proto
26+
}
27+
: null
28+
);
29+
2230
var inspectCustom = require('./util.inspect').custom;
2331
var inspectSymbol = inspectCustom && isSymbol(inspectCustom) ? inspectCustom : null;
32+
var toStringTag = typeof Symbol === 'function' && typeof Symbol.toStringTag === 'symbol' ? Symbol.toStringTag : null;
2433

2534
module.exports = function inspect_(obj, options, depth, seen) {
2635
var opts = options || {};
@@ -178,11 +187,16 @@ module.exports = function inspect_(obj, options, depth, seen) {
178187
}
179188
if (!isDate(obj) && !isRegExp(obj)) {
180189
var ys = arrObjKeys(obj, inspect);
181-
if (ys.length === 0) { return '{}'; }
190+
var isPlainObject = gPO ? gPO(obj) === Object.prototype : obj instanceof Object || obj.constructor === Object;
191+
var protoTag = obj instanceof Object ? '' : 'null prototype';
192+
var stringTag = !isPlainObject && toStringTag && toStringTag in obj ? toStr(obj).slice(8, -1) : protoTag ? 'Object' : '';
193+
var constructorTag = isPlainObject || typeof obj.constructor !== 'function' ? '' : obj.constructor.name ? obj.constructor.name + ' ' : '';
194+
var tag = constructorTag + (stringTag || protoTag ? '[' + [].concat(stringTag || [], protoTag || []).join(': ') + '] ' : '');
195+
if (ys.length === 0) { return tag + '{}'; }
182196
if (indent) {
183-
return '{' + indentedJoin(ys, indent) + '}';
197+
return tag + '{' + indentedJoin(ys, indent) + '}';
184198
}
185-
return '{ ' + ys.join(', ') + ' }';
199+
return tag + '{ ' + ys.join(', ') + ' }';
186200
}
187201
return String(obj);
188202
};

test/toStringTag.js

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
'use strict';
2+
3+
var test = require('tape');
4+
var hasSymbols = require('has-symbols')();
5+
6+
var inspect = require('..');
7+
8+
test('Symbol.toStringTag', { skip: !hasSymbols || typeof Symbol.toStringTag !== 'symbol' }, function (t) {
9+
t.plan(4);
10+
11+
var obj = { a: 1 };
12+
t.equal(inspect(obj), '{ a: 1 }', 'object, no Symbol.toStringTag');
13+
14+
obj[Symbol.toStringTag] = 'foo';
15+
t.equal(inspect(obj), '{ a: 1, [Symbol(Symbol.toStringTag)]: \'foo\' }', 'object with Symbol.toStringTag');
16+
17+
t.test('null objects', { skip: 'toString' in { __proto__: null } }, function (st) {
18+
st.plan(2);
19+
20+
var dict = { __proto__: null, a: 1 };
21+
st.equal(inspect(dict), '[Object: null prototype] { a: 1 }', 'null object with Symbol.toStringTag');
22+
23+
dict[Symbol.toStringTag] = 'Dict';
24+
st.equal(inspect(dict), '[Dict: null prototype] { a: 1, [Symbol(Symbol.toStringTag)]: \'Dict\' }', 'null object with Symbol.toStringTag');
25+
});
26+
27+
t.test('instances', function (st) {
28+
st.plan(4);
29+
30+
function C() {
31+
this.a = 1;
32+
}
33+
st.equal(Object.prototype.toString.call(new C()), '[object Object]', 'instance, no toStringTag, Object.prototype.toString');
34+
st.equal(inspect(new C()), 'C { a: 1 }', 'instance, no toStringTag');
35+
36+
C.prototype[Symbol.toStringTag] = 'Class!';
37+
st.equal(Object.prototype.toString.call(new C()), '[object Class!]', 'instance, with toStringTag, Object.prototype.toString');
38+
st.equal(inspect(new C()), 'C [Class!] { a: 1 }', 'instance, with toStringTag');
39+
});
40+
});

0 commit comments

Comments
 (0)