@samitouri / QOS-React-1 / commits / 53b5c3c9f1

[react-devtools] Fix trailing percent sign in formatConsoleArguments (#36852)

## Summary `formatConsoleArguments` (used by the DevTools backend to inline console substitutions) walks the format string and inlines `%s`/`%d`/`%i`/`%f` arguments while leaving `%c`/`%o`/`%O` in place. For each `%` it reads the **next** character to decide what to do. When the format string ends with a lone `%` — e.g. `console.log('Progress 100%', value)` — the character after `%` is `undefined`, and the `default` branch ran: ```js template += `%${nextChar}`; // -> "%undefined" ``` So the function emitted the literal text `%undefined`: ```js formatConsoleArguments('Progress 100%', 'extra'); // before: ['Progress 100%undefined', 'extra'] // after: ['Progress 100%', 'extra'] ``` Browsers render a trailing `%` in a console format string as a literal percent sign, so this PR keeps it as `%` when there is no following character. ## How did you test this change? Added a `keeps a trailing percent sign` test to the existing `formatConsoleArguments` suite in `utils-test.js` (covering both a bare trailing `%` and one that follows another substitution). Since the function is pure and import-free, I also verified the patched logic against every existing case in that suite plus the new ones to confirm there are no regressions.

udit committed Jun 22, 2026 at 16:29 UTC 53b5c3c9f1cfb04187eaf1182aa1acc5dfe831fa
2 files changed +15 -1
packages/react-devtools-shared/src/__tests__/utils-test.js
+8
@@ -501,5 +501,13 @@ function f() { }
501 formatConsoleArguments('This is the %s template', undefined),
502 ).toEqual(['This is the undefined template']);
503 });
504 +
505 + it('keeps a trailing percent sign', () => {
506 + expect(formatConsoleArguments('Progress 100%', 'extra')).toEqual([
507 + 'Progress 100%',
508 + 'extra',
509 + ]);
510 + expect(formatConsoleArguments('%s 100%', 'done')).toEqual(['done 100%']);
511 + });
512 });
513 });
packages/react-devtools-shared/src/backend/utils/formatConsoleArguments.js
+7 -1
@@ -64,7 +64,13 @@ export default function formatConsoleArguments(
64 }
65
66 default:
67 - template += `%${nextChar}`;
67 + if (nextChar === undefined) {
68 + // A trailing '%' with no following character. Keep it as a literal
69 + // '%' rather than emitting the string 'undefined'.
70 + template += '%';
71 + } else {
72 + template += `%${nextChar}`;
73 + }
74 }
75 }
76