Skip to content

Commit 87f12d6

Browse files
committed
[Fix] use a robust check for a boxed Symbol
1 parent 5753ace commit 87f12d6

File tree

2 files changed

+38
-11
lines changed

2 files changed

+38
-11
lines changed

index.js

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ var functionToString = Function.prototype.toString;
1818
var match = String.prototype.match;
1919
var bigIntValueOf = typeof BigInt === 'function' ? BigInt.prototype.valueOf : null;
2020
var gOPS = Object.getOwnPropertySymbols;
21-
var symToString = typeof Symbol === 'function' ? Symbol.prototype.toString : null;
21+
var symToString = typeof Symbol === 'function' && typeof Symbol.iterator === 'symbol' ? Symbol.prototype.toString : null;
2222
var isEnumerable = Object.prototype.propertyIsEnumerable;
2323

2424
var gPO = (typeof Reflect === 'function' ? Reflect.getPrototypeOf : Object.getPrototypeOf) || (
@@ -194,7 +194,7 @@ module.exports = function inspect_(obj, options, depth, seen) {
194194
var ys = arrObjKeys(obj, inspect);
195195
var isPlainObject = gPO ? gPO(obj) === Object.prototype : obj instanceof Object || obj.constructor === Object;
196196
var protoTag = obj instanceof Object ? '' : 'null prototype';
197-
var stringTag = !isPlainObject && toStringTag && toStringTag in obj ? toStr(obj).slice(8, -1) : protoTag ? 'Object' : '';
197+
var stringTag = !isPlainObject && toStringTag && Object(obj) === obj && toStringTag in obj ? toStr(obj).slice(8, -1) : protoTag ? 'Object' : '';
198198
var constructorTag = isPlainObject || typeof obj.constructor !== 'function' ? '' : obj.constructor.name ? obj.constructor.name + ' ' : '';
199199
var tag = constructorTag + (stringTag || protoTag ? '[' + [].concat(stringTag || [], protoTag || []).join(': ') + '] ' : '');
200200
if (ys.length === 0) { return tag + '{}'; }
@@ -215,17 +215,28 @@ function quote(s) {
215215
return String(s).replace(/"/g, '"');
216216
}
217217

218-
var hasToStringTag = typeof Symbol === 'function' && typeof Symbol.toStringTag === 'symbol';
218+
function isArray(obj) { return toStr(obj) === '[object Array]' && (!toStringTag || !(typeof obj === 'object' && toStringTag in obj)); }
219+
function isDate(obj) { return toStr(obj) === '[object Date]' && (!toStringTag || !(typeof obj === 'object' && toStringTag in obj)); }
220+
function isRegExp(obj) { return toStr(obj) === '[object RegExp]' && (!toStringTag || !(typeof obj === 'object' && toStringTag in obj)); }
221+
function isError(obj) { return toStr(obj) === '[object Error]' && (!toStringTag || !(typeof obj === 'object' && toStringTag in obj)); }
222+
function isString(obj) { return toStr(obj) === '[object String]' && (!toStringTag || !(typeof obj === 'object' && toStringTag in obj)); }
223+
function isNumber(obj) { return toStr(obj) === '[object Number]' && (!toStringTag || !(typeof obj === 'object' && toStringTag in obj)); }
224+
function isBoolean(obj) { return toStr(obj) === '[object Boolean]' && (!toStringTag || !(typeof obj === 'object' && toStringTag in obj)); }
219225

220-
function isArray(obj) { return toStr(obj) === '[object Array]' && (!hasToStringTag || !(Symbol.toStringTag in obj)); }
221-
function isDate(obj) { return toStr(obj) === '[object Date]' && (!hasToStringTag || !(Symbol.toStringTag in obj)); }
222-
function isRegExp(obj) { return toStr(obj) === '[object RegExp]' && (!hasToStringTag || !(Symbol.toStringTag in obj)); }
223-
function isError(obj) { return toStr(obj) === '[object Error]' && (!hasToStringTag || !(Symbol.toStringTag in obj)); }
224-
function isString(obj) { return toStr(obj) === '[object String]' && (!hasToStringTag || !(Symbol.toStringTag in obj)); }
225-
function isNumber(obj) { return toStr(obj) === '[object Number]' && (!hasToStringTag || !(Symbol.toStringTag in obj)); }
226-
function isBoolean(obj) { return toStr(obj) === '[object Boolean]' && (!hasToStringTag || !(Symbol.toStringTag in obj)); }
227226
// Symbol and BigInt do have Symbol.toStringTag by spec, so that can't be used to eliminate false positives
228-
function isSymbol(obj) { return toStr(obj) === '[object Symbol]'; }
227+
function isSymbol(obj) {
228+
if (typeof obj === 'symbol') {
229+
return true;
230+
}
231+
if (!obj || typeof obj !== 'object' || !symToString) {
232+
return false;
233+
}
234+
try {
235+
symToString.call(obj);
236+
return true;
237+
} catch (e) {}
238+
return false;
239+
}
229240

230241
function isBigInt(obj) {
231242
if (!obj || typeof obj !== 'object' || !bigIntValueOf) {

test/values.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
1+
'use strict';
2+
13
var inspect = require('../');
24
var test = require('tape');
5+
var hasSymbols = require('has-symbols')();
36

47
test('values', function (t) {
58
t.plan(1);
@@ -69,6 +72,19 @@ test('symbols', { skip: typeof Symbol !== 'function' }, function (t) {
6972
var sym = Symbol('foo');
7073
t.equal(inspect(sym), 'Symbol(foo)', 'Symbol("foo") should be "Symbol(foo)"');
7174
t.equal(inspect(Object(sym)), 'Object(Symbol(foo))', 'Object(Symbol("foo")) should be "Object(Symbol(foo))"');
75+
76+
t.test('toStringTag', { skip: !hasSymbols || typeof Symbol.toStringTag !== 'symbol' }, function (st) {
77+
st.plan(1);
78+
79+
var faker = {};
80+
faker[Symbol.toStringTag] = 'Symbol';
81+
st.equal(
82+
inspect(faker),
83+
'{ [Symbol(Symbol.toStringTag)]: \'Symbol\' }',
84+
'object lying about being a Symbol inspects as an object'
85+
);
86+
});
87+
7288
t.end();
7389
});
7490

0 commit comments

Comments
 (0)