Skip to content

Commit 4acfc2c

Browse files
committed
[Fix] handle core-js Symbol shams
1 parent 95c323a commit 4acfc2c

File tree

10 files changed

+82
-31
lines changed

10 files changed

+82
-31
lines changed

.github/workflows/node-iojs.yml

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ jobs:
1212
- uses: ljharb/actions/node/matrix@main
1313
id: set-matrix
1414
with:
15+
versionsAsRoot: true
1516
preset: 'iojs'
1617

1718
latest:
@@ -21,7 +22,11 @@ jobs:
2122

2223
strategy:
2324
fail-fast: false
24-
matrix: ${{ fromJson(needs.matrix.outputs.latest) }}
25+
matrix:
26+
node-version: ${{ fromJson(needs.matrix.outputs.latest) }}
27+
command:
28+
- 'tests-only'
29+
- 'test:corejs'
2530

2631
steps:
2732
- uses: actions/checkout@v2
@@ -30,7 +35,7 @@ jobs:
3035
with:
3136
node-version: ${{ matrix.node-version }}
3237
skip-ls-check: true
33-
- run: npm run tests-only
38+
- run: npm run ${{ matrix.command }}
3439
- uses: codecov/codecov-action@v1
3540

3641
minors:
@@ -42,7 +47,11 @@ jobs:
4247

4348
strategy:
4449
fail-fast: false
45-
matrix: ${{ fromJson(needs.matrix.outputs.minors) }}
50+
matrix:
51+
node-version: ${{ fromJson(needs.matrix.outputs.minors) }}
52+
command:
53+
- 'tests-only'
54+
- 'test:corejs'
4655

4756
steps:
4857
- uses: actions/checkout@v2
@@ -51,7 +60,7 @@ jobs:
5160
with:
5261
node-version: ${{ matrix.node-version }}
5362
skip-ls-check: true
54-
- run: npm run tests-only
63+
- run: npm run ${{ matrix.command }}
5564
- uses: codecov/codecov-action@v1
5665

5766
node:

.github/workflows/node-zero.yml

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ jobs:
1212
- uses: ljharb/actions/node/matrix@main
1313
id: set-matrix
1414
with:
15+
versionsAsRoot: true
1516
preset: '0.x'
1617

1718
stable:
@@ -21,7 +22,11 @@ jobs:
2122

2223
strategy:
2324
fail-fast: false
24-
matrix: ${{ fromJson(needs.matrix.outputs.stable) }}
25+
matrix:
26+
node-version: ${{ fromJson(needs.matrix.outputs.stable) }}
27+
command:
28+
- 'tests-only'
29+
- 'test:corejs'
2530

2631
steps:
2732
- uses: actions/checkout@v2
@@ -31,7 +36,7 @@ jobs:
3136
node-version: ${{ matrix.node-version }}
3237
cache-node-modules-key: node_modules-${{ github.workflow }}-${{ github.action }}-${{ github.run_id }}
3338
skip-ls-check: true
34-
- run: npm run tests-only
39+
- run: npm run ${{ matrix.command }}
3540
- uses: codecov/codecov-action@v1
3641

3742
unstable:
@@ -43,7 +48,11 @@ jobs:
4348

4449
strategy:
4550
fail-fast: false
46-
matrix: ${{ fromJson(needs.matrix.outputs.unstable) }}
51+
matrix:
52+
node-version: ${{ fromJson(needs.matrix.outputs.unstable) }}
53+
command:
54+
- 'tests-only'
55+
- 'test:corejs'
4756

4857
steps:
4958
- uses: actions/checkout@v2
@@ -53,7 +62,7 @@ jobs:
5362
node-version: ${{ matrix.node-version }}
5463
cache-node-modules-key: node_modules-${{ github.workflow }}-${{ github.action }}-${{ github.run_id }}
5564
skip-ls-check: true
56-
- run: npm run tests-only
65+
- run: npm run ${{ matrix.command }}
5766
- uses: codecov/codecov-action@v1
5867

5968
node:

.npmignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,5 @@ coverage
1111
.nyc_output
1212

1313
.github/workflows
14+
15+
./test-core-js.js

index.js

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ var match = String.prototype.match;
1919
var bigIntValueOf = typeof BigInt === 'function' ? BigInt.prototype.valueOf : null;
2020
var gOPS = Object.getOwnPropertySymbols;
2121
var symToString = typeof Symbol === 'function' && typeof Symbol.iterator === 'symbol' ? Symbol.prototype.toString : null;
22+
var hasShammedSymbols = typeof Symbol === 'function' && typeof Symbol.iterator === 'object';
2223
var isEnumerable = Object.prototype.propertyIsEnumerable;
2324

2425
var gPO = (typeof Reflect === 'function' ? Reflect.getPrototypeOf : Object.getPrototypeOf) || (
@@ -31,7 +32,7 @@ var gPO = (typeof Reflect === 'function' ? Reflect.getPrototypeOf : Object.getPr
3132

3233
var inspectCustom = require('./util.inspect').custom;
3334
var inspectSymbol = inspectCustom && isSymbol(inspectCustom) ? inspectCustom : null;
34-
var toStringTag = typeof Symbol === 'function' && typeof Symbol.toStringTag === 'symbol' ? Symbol.toStringTag : null;
35+
var toStringTag = typeof Symbol === 'function' && typeof Symbol.toStringTag !== 'undefined' ? Symbol.toStringTag : null;
3536

3637
module.exports = function inspect_(obj, options, depth, seen) {
3738
var opts = options || {};
@@ -121,8 +122,8 @@ module.exports = function inspect_(obj, options, depth, seen) {
121122
return '[Function' + (name ? ': ' + name : ' (anonymous)') + ']' + (keys.length > 0 ? ' { ' + keys.join(', ') + ' }' : '');
122123
}
123124
if (isSymbol(obj)) {
124-
var symString = symToString.call(obj);
125-
return typeof obj === 'object' ? markBoxed(symString) : symString;
125+
var symString = hasShammedSymbols ? String(obj).replace(/^(Symbol\(.*\))_[^)]*$/, '$1') : symToString.call(obj);
126+
return typeof obj === 'object' && !hasShammedSymbols ? markBoxed(symString) : symString;
126127
}
127128
if (isElement(obj)) {
128129
var s = '<' + String(obj.nodeName).toLowerCase();
@@ -225,6 +226,9 @@ function isBoolean(obj) { return toStr(obj) === '[object Boolean]' && (!toString
225226

226227
// Symbol and BigInt do have Symbol.toStringTag by spec, so that can't be used to eliminate false positives
227228
function isSymbol(obj) {
229+
if (hasShammedSymbols) {
230+
return obj && typeof obj === 'object' && obj instanceof Symbol;
231+
}
228232
if (typeof obj === 'symbol') {
229233
return true;
230234
}
@@ -432,17 +436,28 @@ function arrObjKeys(obj, inspect) {
432436
xs[i] = has(obj, i) ? inspect(obj[i], obj) : '';
433437
}
434438
}
439+
var syms = typeof gOPS === 'function' ? gOPS(obj) : [];
440+
var symMap;
441+
if (hasShammedSymbols) {
442+
symMap = {};
443+
for (var k = 0; k < syms.length; k++) {
444+
symMap['$' + syms[k]] = syms[k];
445+
}
446+
}
447+
435448
for (var key in obj) { // eslint-disable-line no-restricted-syntax
436449
if (!has(obj, key)) { continue; } // eslint-disable-line no-restricted-syntax, no-continue
437450
if (isArr && String(Number(key)) === key && key < obj.length) { continue; } // eslint-disable-line no-restricted-syntax, no-continue
438-
if ((/[^\w$]/).test(key)) {
451+
if (hasShammedSymbols && symMap['$' + key] instanceof Symbol) {
452+
// this is to prevent shammed Symbols, which are stored as strings, from being included in the string key section
453+
continue; // eslint-disable-line no-restricted-syntax, no-continue
454+
} else if ((/[^\w$]/).test(key)) {
439455
xs.push(inspect(key, obj) + ': ' + inspect(obj[key], obj));
440456
} else {
441457
xs.push(key + ': ' + inspect(obj[key], obj));
442458
}
443459
}
444460
if (typeof gOPS === 'function') {
445-
var syms = gOPS(obj);
446461
for (var j = 0; j < syms.length; j++) {
447462
if (isEnumerable.call(obj, syms[j])) {
448463
xs.push('[' + inspect(syms[j]) + ']: ' + inspect(obj[syms[j]], obj));

package.json

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,9 @@
2121
"prepublishOnly": "safe-publish-latest",
2222
"pretest": "npm run lint",
2323
"lint": "eslint .",
24-
"test": "npm run tests-only",
25-
"tests-only": "nyc npm run tests-only:tape",
26-
"pretests-only:tape": "node test-core-js",
27-
"tests-only:tape": "tape 'test/*.js'",
24+
"test": "npm run tests-only && npm run test:corejs",
25+
"tests-only": "nyc tape 'test/*.js'",
26+
"test:corejs": "nyc tape test-core-js.js 'test/*.js'",
2827
"posttest": "npx aud --production"
2928
},
3029
"testling": {

test/bigint.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
var inspect = require('../');
44
var test = require('tape');
5-
var hasSymbols = require('has-symbols')();
5+
var hasSymbols = require('has-symbols/shams')();
66

77
test('bigint', { skip: typeof BigInt === 'undefined' }, function (t) {
88
t.test('primitives', function (st) {
@@ -30,7 +30,7 @@ test('bigint', { skip: typeof BigInt === 'undefined' }, function (t) {
3030
st.equal(inspect(Function('return 256n')()), '256n');
3131
});
3232

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

3636
var faker = {};

test/fakes.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@
22

33
var inspect = require('../');
44
var test = require('tape');
5-
var hasSymbols = require('has-symbols')();
5+
var hasSymbols = require('has-symbols/shams')();
66
var forEach = require('for-each');
77

8-
test('fakes', { skip: !hasSymbols || typeof Symbol.toStringTag !== 'symbol' }, function (t) {
8+
test('fakes', { skip: !hasSymbols || typeof Symbol.toStringTag === 'undefined' }, function (t) {
99
forEach([
1010
'Array',
1111
'Boolean',

test/inspect.js

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
var test = require('tape');
2-
var hasSymbols = require('has-symbols')();
2+
var hasSymbols = require('has-symbols/shams')();
33
var utilInspect = require('../util.inspect');
44
var repeat = require('string.prototype.repeat');
55

@@ -43,8 +43,22 @@ test('symbols', { skip: !hasSymbols }, function (t) {
4343
value: 4
4444
});
4545

46-
t.equal(inspect(obj), '{ a: 1, [Symbol(test)]: 2, [Symbol(Symbol.iterator)]: 3 }', 'object with symbols');
47-
t.equal(inspect([obj, []]), '[ { a: 1, [Symbol(test)]: 2, [Symbol(Symbol.iterator)]: 3 }, [] ]', 'object with symbols');
46+
if (typeof Symbol.iterator === 'symbol') {
47+
t.equal(inspect(obj), '{ a: 1, [Symbol(test)]: 2, [Symbol(Symbol.iterator)]: 3 }', 'object with symbols');
48+
t.equal(inspect([obj, []]), '[ { a: 1, [Symbol(test)]: 2, [Symbol(Symbol.iterator)]: 3 }, [] ]', 'object with symbols in array');
49+
} else {
50+
// symbol sham key ordering is unreliable
51+
t.match(
52+
inspect(obj),
53+
/^(?:{ a: 1, \[Symbol\(test\)\]: 2, \[Symbol\(Symbol.iterator\)\]: 3 }|{ a: 1, \[Symbol\(Symbol.iterator\)\]: 3, \[Symbol\(test\)\]: 2 })$/,
54+
'object with symbols (nondeterministic symbol sham key ordering)'
55+
);
56+
t.match(
57+
inspect([obj, []]),
58+
/^\[ (?:{ a: 1, \[Symbol\(test\)\]: 2, \[Symbol\(Symbol.iterator\)\]: 3 }|{ a: 1, \[Symbol\(Symbol.iterator\)\]: 3, \[Symbol\(test\)\]: 2 }), \[\] \]$/,
59+
'object with symbols in array (nondeterministic symbol sham key ordering)'
60+
);
61+
}
4862
});
4963

5064
test('maxStringLength', function (t) {

test/toStringTag.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
'use strict';
22

33
var test = require('tape');
4-
var hasSymbols = require('has-symbols')();
4+
var hasSymbols = require('has-symbols/shams')();
55

6-
var inspect = require('..');
6+
var inspect = require('../');
77

8-
test('Symbol.toStringTag', { skip: !hasSymbols || typeof Symbol.toStringTag !== 'symbol' }, function (t) {
8+
test('Symbol.toStringTag', { skip: !hasSymbols || typeof Symbol.toStringTag === 'undefined' }, function (t) {
99
t.plan(4);
1010

1111
var obj = { a: 1 };

test/values.js

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
var inspect = require('../');
44
var test = require('tape');
5-
var hasSymbols = require('has-symbols')();
5+
var hasSymbols = require('has-symbols/shams')();
66

77
test('values', function (t) {
88
t.plan(1);
@@ -68,12 +68,15 @@ test('seen seen seen', function (t) {
6868
);
6969
});
7070

71-
test('symbols', { skip: typeof Symbol !== 'function' }, function (t) {
71+
test('symbols', { skip: !hasSymbols }, function (t) {
7272
var sym = Symbol('foo');
7373
t.equal(inspect(sym), 'Symbol(foo)', 'Symbol("foo") should be "Symbol(foo)"');
74-
t.equal(inspect(Object(sym)), 'Object(Symbol(foo))', 'Object(Symbol("foo")) should be "Object(Symbol(foo))"');
74+
if (typeof sym === 'symbol') {
75+
// Symbol shams are incapable of differentiating boxed from unboxed symbols
76+
t.equal(inspect(Object(sym)), 'Object(Symbol(foo))', 'Object(Symbol("foo")) should be "Object(Symbol(foo))"');
77+
}
7578

76-
t.test('toStringTag', { skip: !hasSymbols || typeof Symbol.toStringTag !== 'symbol' }, function (st) {
79+
t.test('toStringTag', { skip: !hasSymbols || typeof Symbol.toStringTag === 'undefined' }, function (st) {
7780
st.plan(1);
7881

7982
var faker = {};

0 commit comments

Comments
 (0)