util: fix `%s` format behavior with `Symbol.toPrimitive`

This commit ensures `console.log("%s", obj)` correctly invokes
`obj[Symbol.toPrimitive]` for string conversion, fixing unexpected
object display issue.

PR-URL: https://github.com/nodejs/node/pull/50992
Fixes: https://github.com/nodejs/node/issues/50909
Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Zeyu "Alex" Yang <himself65@outlook.com>
This commit is contained in:
Chenyu Yang 2024-03-18 14:54:58 +08:00 committed by Antoine du Hamel
parent 06cde5c902
commit dde2965765
No known key found for this signature in database
GPG Key ID: 21D900FFDB233756
2 changed files with 27 additions and 0 deletions

View File

@ -87,6 +87,7 @@ const {
SymbolIterator,
SymbolPrototypeToString,
SymbolPrototypeValueOf,
SymbolToPrimitive,
SymbolToStringTag,
TypedArrayPrototypeGetLength,
TypedArrayPrototypeGetSymbolToStringTag,
@ -2103,6 +2104,11 @@ function hasBuiltInToString(value) {
value = proxyTarget;
}
// Check if value has a custom Symbol.toPrimitive transformation.
if (typeof value[SymbolToPrimitive] === 'function') {
return false;
}
// Count objects that have no `toString` function as built-in.
if (typeof value.toString !== 'function') {
return true;

View File

@ -269,6 +269,27 @@ assert.strictEqual(util.format('%s', -Infinity), '-Infinity');
);
}
// Symbol.toPrimitive handling for string format specifier
{
const objectWithToPrimitive = {
[Symbol.toPrimitive](hint) {
switch (hint) {
case 'number':
return 42;
case 'string':
return 'string representation';
case 'default':
default:
return 'default context';
}
}
};
assert.strictEqual(util.format('%s', +objectWithToPrimitive), '42');
assert.strictEqual(util.format('%s', objectWithToPrimitive), 'string representation');
assert.strictEqual(util.format('%s', objectWithToPrimitive + ''), 'default context');
}
// JSON format specifier
assert.strictEqual(util.format('%j'), '%j');
assert.strictEqual(util.format('%j', 42), '42');