Skip to content

Commit ae2333d

Browse files
BridgeARtargos
authored andcommitted
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: #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>
1 parent e7026f1 commit ae2333d

File tree

2 files changed

+56
-28
lines changed

2 files changed

+56
-28
lines changed

lib/internal/util/inspect.js

Lines changed: 42 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -385,8 +385,6 @@ function getPrefix(constructor, tag, fallback) {
385385
return `${constructor} `;
386386
}
387387

388-
const getBoxedValue = formatPrimitive.bind(null, stylizeNoColor);
389-
390388
// Look up the keys of the object.
391389
function getKeys(value, showHidden) {
392390
let keys;
@@ -709,31 +707,9 @@ function formatRaw(ctx, value, recurseTimes, typedArray) {
709707
braces[0] = `[${tag}] {`;
710708
formatter = formatNamespaceObject;
711709
} else if (isBoxedPrimitive(value)) {
712-
let type;
713-
if (isNumberObject(value)) {
714-
base = `[Number: ${getBoxedValue(NumberPrototype.valueOf(value))}]`;
715-
type = 'number';
716-
} else if (isStringObject(value)) {
717-
base = `[String: ${
718-
getBoxedValue(StringPrototype.valueOf(value), ctx)
719-
}]`;
720-
type = 'string';
721-
// For boxed Strings, we have to remove the 0-n indexed entries,
722-
// since they just noisy up the output and are redundant
723-
// Make boxed primitive Strings look like such
724-
keys = keys.slice(value.length);
725-
} else if (isBooleanObject(value)) {
726-
base = `[Boolean: ${getBoxedValue(BooleanPrototype.valueOf(value))}]`;
727-
type = 'boolean';
728-
} else if (isBigIntObject(value)) {
729-
base = `[BigInt: ${getBoxedValue(BigIntPrototype.valueOf(value))}]`;
730-
type = 'bigint';
731-
} else {
732-
base = `[Symbol: ${getBoxedValue(SymbolPrototype.valueOf(value))}]`;
733-
type = 'symbol';
734-
}
710+
base = getBoxedBase(value, ctx, keys, constructor, tag);
735711
if (keys.length === 0) {
736-
return ctx.stylize(base, type);
712+
return base;
737713
}
738714
} else {
739715
// The input prototype got manipulated. Special handle these. We have to
@@ -818,6 +794,46 @@ function getIteratorBraces(type, tag) {
818794
return [`[${tag}] {`, '}'];
819795
}
820796

797+
function getBoxedBase(value, ctx, keys, constructor, tag) {
798+
let fn;
799+
let type;
800+
if (isNumberObject(value)) {
801+
fn = NumberPrototype;
802+
type = 'Number';
803+
} else if (isStringObject(value)) {
804+
fn = StringPrototype;
805+
type = 'String';
806+
// For boxed Strings, we have to remove the 0-n indexed entries,
807+
// since they just noisy up the output and are redundant
808+
// Make boxed primitive Strings look like such
809+
keys.splice(0, value.length);
810+
} else if (isBooleanObject(value)) {
811+
fn = BooleanPrototype;
812+
type = 'Boolean';
813+
} else if (isBigIntObject(value)) {
814+
fn = BigIntPrototype;
815+
type = 'BigInt';
816+
} else {
817+
fn = SymbolPrototype;
818+
type = 'Symbol';
819+
}
820+
let base = `[${type}`;
821+
if (type !== constructor) {
822+
if (constructor === null) {
823+
base += ' (null prototype)';
824+
} else {
825+
base += ` (${constructor})`;
826+
}
827+
}
828+
base += `: ${formatPrimitive(stylizeNoColor, fn.valueOf(value), ctx)}]`;
829+
if (tag !== '' && tag !== constructor) {
830+
base += ` [${tag}]`;
831+
}
832+
if (keys.length !== 0 || ctx.stylize === stylizeNoColor)
833+
return base;
834+
return ctx.stylize(base, type.toLowerCase());
835+
}
836+
821837
function formatError(err, constructor, tag, ctx) {
822838
// TODO(BridgeAR): Always show the error code if present.
823839
let stack = err.stack || ErrorPrototype.toString(err);

test/parallel/test-util-inspect.js

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -856,9 +856,21 @@ assert.strictEqual(
856856
'[Symbol: Symbol(test)]'
857857
);
858858
assert.strictEqual(util.inspect(new Boolean(false)), '[Boolean: false]');
859-
assert.strictEqual(util.inspect(new Boolean(true)), '[Boolean: true]');
859+
assert.strictEqual(
860+
util.inspect(Object.setPrototypeOf(new Boolean(true), null)),
861+
'[Boolean (null prototype): true]'
862+
);
860863
assert.strictEqual(util.inspect(new Number(0)), '[Number: 0]');
861-
assert.strictEqual(util.inspect(new Number(-0)), '[Number: -0]');
864+
assert.strictEqual(
865+
util.inspect(
866+
Object.defineProperty(
867+
Object.setPrototypeOf(new Number(-0), Array.prototype),
868+
Symbol.toStringTag,
869+
{ value: 'Foobar' }
870+
)
871+
),
872+
'[Number (Array): -0] [Foobar]'
873+
);
862874
assert.strictEqual(util.inspect(new Number(-1.1)), '[Number: -1.1]');
863875
assert.strictEqual(util.inspect(new Number(13.37)), '[Number: 13.37]');
864876

0 commit comments

Comments
 (0)