Skip to content

Commit 73f3a1c

Browse files
BridgeARtargos
authored andcommitted
util: make inspect aware of RegExp subclasses and null prototype
This adds support for inspect to distinguish regular expression subclasses and ones with null prototype from "normal" regular expressions. PR-URL: #25192 Reviewed-By: Anto Aravinth <anto.aravinth.cse@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com>
1 parent 58af085 commit 73f3a1c

File tree

3 files changed

+39
-13
lines changed

3 files changed

+39
-13
lines changed

lib/internal/util/inspect.js

+5-2
Original file line numberDiff line numberDiff line change
@@ -634,9 +634,12 @@ function formatRaw(ctx, value, recurseTimes) {
634634
base = `[${name}]`;
635635
} else if (isRegExp(value)) {
636636
// Make RegExps say that they are RegExps
637+
base = regExpToString(constructor !== null ? value : new RegExp(value));
638+
const prefix = getPrefix(constructor, tag, 'RegExp');
639+
if (prefix !== 'RegExp ')
640+
base = `${prefix}${base}`;
637641
if (keys.length === 0 || recurseTimes < 0)
638-
return ctx.stylize(regExpToString(value), 'regexp');
639-
base = `${regExpToString(value)}`;
642+
return ctx.stylize(base, 'regexp');
640643
} else if (isDate(value)) {
641644
// Make dates with properties first say the date
642645
if (keys.length === 0) {

test/parallel/test-assert-deep.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ assert.throws(
149149
{
150150
code: 'ERR_ASSERTION',
151151
message: `${defaultMsgStartFull}\n\n` +
152-
"+ /test/\n- /test/ {\n- '0': '1'\n- }"
152+
"+ /test/\n- MyRegExp /test/ {\n- '0': '1'\n- }"
153153
}
154154
);
155155

test/parallel/test-util-inspect.js

+33-10
Original file line numberDiff line numberDiff line change
@@ -1580,15 +1580,7 @@ assert.strictEqual(util.inspect('"\''), '`"\'`');
15801580
// eslint-disable-next-line no-template-curly-in-string
15811581
assert.strictEqual(util.inspect('"\'${a}'), "'\"\\'${a}'");
15821582

1583-
{
1584-
assert.strictEqual(
1585-
util.inspect(Object.setPrototypeOf(/a/, null)),
1586-
'/undefined/undefined'
1587-
);
1588-
}
1589-
1590-
// Verify that throwing in valueOf and having no prototype still produces nice
1591-
// results.
1583+
// Verify that throwing in valueOf and toString still produces nice results.
15921584
[
15931585
[new String(55), "[String: '55']"],
15941586
[new Boolean(true), '[Boolean: true]'],
@@ -1609,6 +1601,7 @@ assert.strictEqual(util.inspect('"\'${a}'), "'\"\\'${a}'");
16091601
[new Promise((resolve) => setTimeout(resolve, 10)), 'Promise { <pending> }'],
16101602
[new WeakSet(), 'WeakSet { <items unknown> }'],
16111603
[new WeakMap(), 'WeakMap { <items unknown> }'],
1604+
[/foobar/g, '/foobar/g']
16121605
].forEach(([value, expected]) => {
16131606
Object.defineProperty(value, 'valueOf', {
16141607
get() {
@@ -1628,6 +1621,7 @@ assert.strictEqual(util.inspect('"\'${a}'), "'\"\\'${a}'");
16281621
assert.notStrictEqual(util.inspect(value), expected);
16291622
});
16301623

1624+
// Verify that having no prototype still produces nice results.
16311625
[
16321626
[[1, 3, 4], '[Array: null prototype] [ 1, 3, 4 ]'],
16331627
[new Set([1, 2]), '[Set: null prototype] { 1, 2 }'],
@@ -1652,7 +1646,8 @@ assert.strictEqual(util.inspect('"\'${a}'), "'\"\\'${a}'");
16521646
'[DataView: null prototype] {\n byteLength: undefined,\n ' +
16531647
'byteOffset: undefined,\n buffer: undefined }'],
16541648
[new SharedArrayBuffer(2), '[SharedArrayBuffer: null prototype] ' +
1655-
'{ byteLength: undefined }']
1649+
'{ byteLength: undefined }'],
1650+
[/foobar/, '[RegExp: null prototype] /foobar/']
16561651
].forEach(([value, expected]) => {
16571652
assert.strictEqual(
16581653
util.inspect(Object.setPrototypeOf(value, null)),
@@ -1665,6 +1660,34 @@ assert.strictEqual(util.inspect('"\'${a}'), "'\"\\'${a}'");
16651660
assert.notStrictEqual(util.inspect(value), expected);
16661661
});
16671662

1663+
// Verify that subclasses with and without prototype produce nice results.
1664+
[
1665+
[RegExp, ['foobar', 'g'], '/foobar/g']
1666+
].forEach(([base, input, rawExpected]) => {
1667+
class Foo extends base {}
1668+
const value = new Foo(...input);
1669+
const symbol = value[Symbol.toStringTag];
1670+
const expected = `Foo ${symbol ? `[${symbol}] ` : ''}${rawExpected}`;
1671+
const expectedWithoutProto = `[${base.name}: null prototype] ${rawExpected}`;
1672+
assert.strictEqual(util.inspect(value), expected);
1673+
value.foo = 'bar';
1674+
assert.notStrictEqual(util.inspect(value), expected);
1675+
delete value.foo;
1676+
assert.strictEqual(
1677+
util.inspect(Object.setPrototypeOf(value, null)),
1678+
expectedWithoutProto
1679+
);
1680+
value.foo = 'bar';
1681+
let res = util.inspect(value);
1682+
assert.notStrictEqual(res, expectedWithoutProto);
1683+
assert(/foo: 'bar'/.test(res), res);
1684+
delete value.foo;
1685+
value[Symbol('foo')] = 'yeah';
1686+
res = util.inspect(value);
1687+
assert.notStrictEqual(res, expectedWithoutProto);
1688+
assert(/\[Symbol\(foo\)]: 'yeah'/.test(res), res);
1689+
});
1690+
16681691
assert.strictEqual(inspect(1n), '1n');
16691692
assert.strictEqual(inspect(Object(-1n)), '[BigInt: -1n]');
16701693
assert.strictEqual(inspect(Object(13n)), '[BigInt: 13n]');

0 commit comments

Comments
 (0)