util: add prototype support for boxed primitives

This makes sure manipulated prototypes from boxed primitives will
be highlighted. It also makes sure that a potential `Symbol.toStringTag`
is taken into account.

PR-URL: https://github.com/nodejs/node/pull/27351
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: John-David Dalton <john.david.dalton@gmail.com>
Reviewed-By: Anto Aravinth <anto.aravinth.cse@gmail.com>
This commit is contained in:
Ruben Bridgewater 2019-04-22 23:29:56 +02:00
parent d04b376717
commit 55147d7d99
No known key found for this signature in database
GPG Key ID: F07496B3EB3C1762
2 changed files with 56 additions and 28 deletions

View File

@ -385,8 +385,6 @@ function getPrefix(constructor, tag, fallback) {
return `${constructor} `;
}
const getBoxedValue = formatPrimitive.bind(null, stylizeNoColor);
// Look up the keys of the object.
function getKeys(value, showHidden) {
let keys;
@ -709,31 +707,9 @@ function formatRaw(ctx, value, recurseTimes, typedArray) {
braces[0] = `[${tag}] {`;
formatter = formatNamespaceObject;
} else if (isBoxedPrimitive(value)) {
let type;
if (isNumberObject(value)) {
base = `[Number: ${getBoxedValue(NumberPrototype.valueOf(value))}]`;
type = 'number';
} else if (isStringObject(value)) {
base = `[String: ${
getBoxedValue(StringPrototype.valueOf(value), ctx)
}]`;
type = 'string';
// For boxed Strings, we have to remove the 0-n indexed entries,
// since they just noisy up the output and are redundant
// Make boxed primitive Strings look like such
keys = keys.slice(value.length);
} else if (isBooleanObject(value)) {
base = `[Boolean: ${getBoxedValue(BooleanPrototype.valueOf(value))}]`;
type = 'boolean';
} else if (isBigIntObject(value)) {
base = `[BigInt: ${getBoxedValue(BigIntPrototype.valueOf(value))}]`;
type = 'bigint';
} else {
base = `[Symbol: ${getBoxedValue(SymbolPrototype.valueOf(value))}]`;
type = 'symbol';
}
base = getBoxedBase(value, ctx, keys, constructor, tag);
if (keys.length === 0) {
return ctx.stylize(base, type);
return base;
}
} else {
// The input prototype got manipulated. Special handle these. We have to
@ -818,6 +794,46 @@ function getIteratorBraces(type, tag) {
return [`[${tag}] {`, '}'];
}
function getBoxedBase(value, ctx, keys, constructor, tag) {
let fn;
let type;
if (isNumberObject(value)) {
fn = NumberPrototype;
type = 'Number';
} else if (isStringObject(value)) {
fn = StringPrototype;
type = 'String';
// For boxed Strings, we have to remove the 0-n indexed entries,
// since they just noisy up the output and are redundant
// Make boxed primitive Strings look like such
keys.splice(0, value.length);
} else if (isBooleanObject(value)) {
fn = BooleanPrototype;
type = 'Boolean';
} else if (isBigIntObject(value)) {
fn = BigIntPrototype;
type = 'BigInt';
} else {
fn = SymbolPrototype;
type = 'Symbol';
}
let base = `[${type}`;
if (type !== constructor) {
if (constructor === null) {
base += ' (null prototype)';
} else {
base += ` (${constructor})`;
}
}
base += `: ${formatPrimitive(stylizeNoColor, fn.valueOf(value), ctx)}]`;
if (tag !== '' && tag !== constructor) {
base += ` [${tag}]`;
}
if (keys.length !== 0 || ctx.stylize === stylizeNoColor)
return base;
return ctx.stylize(base, type.toLowerCase());
}
function formatError(err, constructor, tag, ctx) {
// TODO(BridgeAR): Always show the error code if present.
let stack = err.stack || ErrorPrototype.toString(err);

View File

@ -856,9 +856,21 @@ assert.strictEqual(
'[Symbol: Symbol(test)]'
);
assert.strictEqual(util.inspect(new Boolean(false)), '[Boolean: false]');
assert.strictEqual(util.inspect(new Boolean(true)), '[Boolean: true]');
assert.strictEqual(
util.inspect(Object.setPrototypeOf(new Boolean(true), null)),
'[Boolean (null prototype): true]'
);
assert.strictEqual(util.inspect(new Number(0)), '[Number: 0]');
assert.strictEqual(util.inspect(new Number(-0)), '[Number: -0]');
assert.strictEqual(
util.inspect(
Object.defineProperty(
Object.setPrototypeOf(new Number(-0), Array.prototype),
Symbol.toStringTag,
{ value: 'Foobar' }
)
),
'[Number (Array): -0] [Foobar]'
);
assert.strictEqual(util.inspect(new Number(-1.1)), '[Number: -1.1]');
assert.strictEqual(util.inspect(new Number(13.37)), '[Number: 13.37]');