Skip to content

Commit

Permalink
util: fix %s format behavior with Symbol.toPrimitive
Browse files Browse the repository at this point in the history
This commit ensures `console.log("%s", obj)` correctly invokes
`obj[Symbol.toPrimitive]` for string conversion, fixing unexpected
object display issue.

PR-URL: #50992
Fixes: #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>
  • Loading branch information
Chenyu Yang authored and marco-ippolito committed Jun 17, 2024
1 parent 800b6f6 commit 7603a51
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 0 deletions.
6 changes: 6 additions & 0 deletions lib/internal/util/inspect.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ const {
SymbolPrototypeToString,
SymbolPrototypeValueOf,
SymbolIterator,
SymbolToPrimitive,
SymbolToStringTag,
TypedArrayPrototypeGetLength,
TypedArrayPrototypeGetSymbolToStringTag,
Expand Down Expand Up @@ -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;
Expand Down
21 changes: 21 additions & 0 deletions test/parallel/test-util-format.js
Original file line number Diff line number Diff line change
Expand Up @@ -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');
Expand Down

0 comments on commit 7603a51

Please sign in to comment.