Skip to content

Commit

Permalink
[Fix] use a robust check for a boxed Symbol
Browse files Browse the repository at this point in the history
  • Loading branch information
ljharb committed Apr 18, 2021
1 parent 5753ace commit 87f12d6
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 11 deletions.
33 changes: 22 additions & 11 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ var functionToString = Function.prototype.toString;
var match = String.prototype.match;
var bigIntValueOf = typeof BigInt === 'function' ? BigInt.prototype.valueOf : null;
var gOPS = Object.getOwnPropertySymbols;
var symToString = typeof Symbol === 'function' ? Symbol.prototype.toString : null;
var symToString = typeof Symbol === 'function' && typeof Symbol.iterator === 'symbol' ? Symbol.prototype.toString : null;
var isEnumerable = Object.prototype.propertyIsEnumerable;

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

var hasToStringTag = typeof Symbol === 'function' && typeof Symbol.toStringTag === 'symbol';
function isArray(obj) { return toStr(obj) === '[object Array]' && (!toStringTag || !(typeof obj === 'object' && toStringTag in obj)); }
function isDate(obj) { return toStr(obj) === '[object Date]' && (!toStringTag || !(typeof obj === 'object' && toStringTag in obj)); }
function isRegExp(obj) { return toStr(obj) === '[object RegExp]' && (!toStringTag || !(typeof obj === 'object' && toStringTag in obj)); }
function isError(obj) { return toStr(obj) === '[object Error]' && (!toStringTag || !(typeof obj === 'object' && toStringTag in obj)); }
function isString(obj) { return toStr(obj) === '[object String]' && (!toStringTag || !(typeof obj === 'object' && toStringTag in obj)); }
function isNumber(obj) { return toStr(obj) === '[object Number]' && (!toStringTag || !(typeof obj === 'object' && toStringTag in obj)); }
function isBoolean(obj) { return toStr(obj) === '[object Boolean]' && (!toStringTag || !(typeof obj === 'object' && toStringTag in obj)); }

function isArray(obj) { return toStr(obj) === '[object Array]' && (!hasToStringTag || !(Symbol.toStringTag in obj)); }
function isDate(obj) { return toStr(obj) === '[object Date]' && (!hasToStringTag || !(Symbol.toStringTag in obj)); }
function isRegExp(obj) { return toStr(obj) === '[object RegExp]' && (!hasToStringTag || !(Symbol.toStringTag in obj)); }
function isError(obj) { return toStr(obj) === '[object Error]' && (!hasToStringTag || !(Symbol.toStringTag in obj)); }
function isString(obj) { return toStr(obj) === '[object String]' && (!hasToStringTag || !(Symbol.toStringTag in obj)); }
function isNumber(obj) { return toStr(obj) === '[object Number]' && (!hasToStringTag || !(Symbol.toStringTag in obj)); }
function isBoolean(obj) { return toStr(obj) === '[object Boolean]' && (!hasToStringTag || !(Symbol.toStringTag in obj)); }
// Symbol and BigInt do have Symbol.toStringTag by spec, so that can't be used to eliminate false positives
function isSymbol(obj) { return toStr(obj) === '[object Symbol]'; }
function isSymbol(obj) {
if (typeof obj === 'symbol') {
return true;
}
if (!obj || typeof obj !== 'object' || !symToString) {
return false;
}
try {
symToString.call(obj);
return true;
} catch (e) {}
return false;
}

function isBigInt(obj) {
if (!obj || typeof obj !== 'object' || !bigIntValueOf) {
Expand Down
16 changes: 16 additions & 0 deletions test/values.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
'use strict';

var inspect = require('../');
var test = require('tape');
var hasSymbols = require('has-symbols')();

test('values', function (t) {
t.plan(1);
Expand Down Expand Up @@ -69,6 +72,19 @@ test('symbols', { skip: typeof Symbol !== 'function' }, function (t) {
var sym = Symbol('foo');
t.equal(inspect(sym), 'Symbol(foo)', 'Symbol("foo") should be "Symbol(foo)"');
t.equal(inspect(Object(sym)), 'Object(Symbol(foo))', 'Object(Symbol("foo")) should be "Object(Symbol(foo))"');

t.test('toStringTag', { skip: !hasSymbols || typeof Symbol.toStringTag !== 'symbol' }, function (st) {
st.plan(1);

var faker = {};
faker[Symbol.toStringTag] = 'Symbol';
st.equal(
inspect(faker),
'{ [Symbol(Symbol.toStringTag)]: \'Symbol\' }',
'object lying about being a Symbol inspects as an object'
);
});

t.end();
});

Expand Down

0 comments on commit 87f12d6

Please sign in to comment.