Skip to content

Commit

Permalink
util: add prototype support for boxed primitives
Browse files Browse the repository at this point in the history
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: #27351
Reviewed-By: Matteo Collina <[email protected]>
Reviewed-By: John-David Dalton <[email protected]>
Reviewed-By: Anto Aravinth <[email protected]>
  • Loading branch information
BridgeAR committed Apr 26, 2019
1 parent d04b376 commit 55147d7
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 28 deletions.
68 changes: 42 additions & 26 deletions lib/internal/util/inspect.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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);
Expand Down
16 changes: 14 additions & 2 deletions test/parallel/test-util-inspect.js
Original file line number Diff line number Diff line change
Expand Up @@ -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]');

Expand Down

0 comments on commit 55147d7

Please sign in to comment.