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:
parent
d04b376717
commit
55147d7d99
@ -385,8 +385,6 @@ function getPrefix(constructor, tag, fallback) {
|
|||||||
return `${constructor} `;
|
return `${constructor} `;
|
||||||
}
|
}
|
||||||
|
|
||||||
const getBoxedValue = formatPrimitive.bind(null, stylizeNoColor);
|
|
||||||
|
|
||||||
// Look up the keys of the object.
|
// Look up the keys of the object.
|
||||||
function getKeys(value, showHidden) {
|
function getKeys(value, showHidden) {
|
||||||
let keys;
|
let keys;
|
||||||
@ -709,31 +707,9 @@ function formatRaw(ctx, value, recurseTimes, typedArray) {
|
|||||||
braces[0] = `[${tag}] {`;
|
braces[0] = `[${tag}] {`;
|
||||||
formatter = formatNamespaceObject;
|
formatter = formatNamespaceObject;
|
||||||
} else if (isBoxedPrimitive(value)) {
|
} else if (isBoxedPrimitive(value)) {
|
||||||
let type;
|
base = getBoxedBase(value, ctx, keys, constructor, tag);
|
||||||
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';
|
|
||||||
}
|
|
||||||
if (keys.length === 0) {
|
if (keys.length === 0) {
|
||||||
return ctx.stylize(base, type);
|
return base;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// The input prototype got manipulated. Special handle these. We have to
|
// The input prototype got manipulated. Special handle these. We have to
|
||||||
@ -818,6 +794,46 @@ function getIteratorBraces(type, tag) {
|
|||||||
return [`[${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) {
|
function formatError(err, constructor, tag, ctx) {
|
||||||
// TODO(BridgeAR): Always show the error code if present.
|
// TODO(BridgeAR): Always show the error code if present.
|
||||||
let stack = err.stack || ErrorPrototype.toString(err);
|
let stack = err.stack || ErrorPrototype.toString(err);
|
||||||
|
@ -856,9 +856,21 @@ assert.strictEqual(
|
|||||||
'[Symbol: Symbol(test)]'
|
'[Symbol: Symbol(test)]'
|
||||||
);
|
);
|
||||||
assert.strictEqual(util.inspect(new Boolean(false)), '[Boolean: false]');
|
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(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(-1.1)), '[Number: -1.1]');
|
||||||
assert.strictEqual(util.inspect(new Number(13.37)), '[Number: 13.37]');
|
assert.strictEqual(util.inspect(new Number(13.37)), '[Number: 13.37]');
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user