diff --git a/lib/utils.js b/lib/utils.js index 897dadd90c..94b2f1bd49 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -138,7 +138,7 @@ function emptyRepresentation(value, typeHint) { * canonicalType(global) // 'global' * canonicalType(new String('foo') // 'object' * canonicalType(async function() {}) // 'asyncfunction' - * canonicalType(await import(name)) // 'module' + * canonicalType(Object.create(null)) // 'null-prototype' */ var canonicalType = (exports.canonicalType = function canonicalType(value) { if (value === undefined) { @@ -147,7 +147,14 @@ var canonicalType = (exports.canonicalType = function canonicalType(value) { return 'null'; } else if (Buffer.isBuffer(value)) { return 'buffer'; + } else if ( + typeof value === 'object' && + // eslint-disable-next-line no-prototype-builtins + !Object.prototype.isPrototypeOf(value) + ) { + return 'null-prototype'; } + return Object.prototype.toString .call(value) .replace(/^\[.+\s(.+?)]$/, '$1') @@ -213,7 +220,7 @@ exports.type = function type(value) { exports.stringify = function (value) { var typeHint = canonicalType(value); - if (!~['object', 'array', 'function', 'module'].indexOf(typeHint)) { + if (!~['object', 'array', 'function', 'null-prototype'].indexOf(typeHint)) { if (typeHint === 'buffer') { var json = Buffer.prototype.toJSON.call(value); // Based on the toJSON result @@ -399,14 +406,12 @@ exports.canonicalize = function canonicalize(value, stack, typeHint) { break; } /* falls through */ - case 'module': - if (value[Symbol.toStringTag] === 'Module') { - canonicalizedObj = canonicalizedObj || {}; - canonicalizedObj['[Symbol.toStringTag]'] = 'Module'; - } - /* falls through */ + case 'null-prototype': case 'object': canonicalizedObj = canonicalizedObj || {}; + if (typeHint === 'null-prototype' && Symbol.toStringTag in value) { + canonicalizedObj['[Symbol.toStringTag]'] = value[Symbol.toStringTag]; + } withStack(value, function () { Object.keys(value) .sort() diff --git a/test/unit/fixtures/module.mjs b/test/unit/fixtures/module.mjs deleted file mode 100644 index bec42311d7..0000000000 --- a/test/unit/fixtures/module.mjs +++ /dev/null @@ -1,4 +0,0 @@ -export default 123; - -export const foo = 'abc'; -export const bar = true; diff --git a/test/unit/utils.spec.js b/test/unit/utils.spec.js index 74020ccf0c..0e54bf394e 100644 --- a/test/unit/utils.spec.js +++ b/test/unit/utils.spec.js @@ -2,8 +2,6 @@ 'use strict'; var utils = require('../../lib/utils'); -const esmUtils = require('../../lib/nodejs/esm-utils'); -const Path = require('node:path'); var sinon = require('sinon'); describe('lib/utils', function () { @@ -291,25 +289,42 @@ describe('lib/utils', function () { expect(stringify(expected), 'to be', actual); }); - it('should represent modules', async function () { - if (process.browser) { - // Current rollup config cannot `import()` - this.skip(); - return; - } - const expected = await esmUtils.requireOrImport( - Path.join(__dirname, './fixtures/module.mjs') - ); - const actual = [ - '{', - ' "[Symbol.toStringTag]": "Module"', - ' "bar": true', - ' "default": 123', - ' "foo": "abc"', - '}' - ].join('\n'); + describe('should represent null prototypes', function () { + it('With explicit names', function () { + const foo = Object.create(null, { + [Symbol.toStringTag]: {value: 'Foo'}, + bing: {get: () => 'bong', enumerable: true} + }); + const expected = [ + '{', + ' "[Symbol.toStringTag]": "Foo"', + ' "bing": "bong"', + '}' + ].join('\n'); + + expect(stringify(foo), 'to be', expected); + }); - expect(stringify(expected), 'to be', actual); + it('Without names', function () { + const unnamed = { + bing: 'bong', + abc: 123 + }; + unnamed.self = unnamed; + const expected = [ + '{', + ' "abc": 123', + ' "bing": "bong"', + ' "self": [Circular]', + '}' + ].join('\n'); + + expect( + stringify(Object.setPrototypeOf(unnamed, null)), + 'to be', + expected + ); + }); }); });