util.styleText() doesn't restore outer styles after nested calls

Version

v23.5.0

Platform

Microsoft Windows NT 10.0.19045.0 x64

Subsystem

util

What steps will reproduce the bug?

node -e "import('node:util').then(({styleText}) => console.log(styleText('red', 'A ' + styleText('blue', 'B') + ' C')))"

How often does it reproduce? Is there a required condition?

Nesting styleText() calls one inside another

What is the expected behavior? Why is that the expected behavior?

After a nested styleText() call ends, the text should return to the outer style, not to the default/unstyled state.

The why:

  1. Major styling libraries (e.g. chalk) handle nesting this way. Devs would expect consistent behavior when migrating to native APIs.
  2. Without proper nesting, styleText() cannot handle "complex" formatting scenarios that are standard in CLI applications

What do you see instead?

When running:

styleText('red', `A ${styleText('blue', 'B')} C`)

Expected output: A(red) B(blue) C(red)
Actual output: A(red) B(blue) C(default color)

The text "C" appears in the terminal's default color instead of returning to red after the nested blue styling ends.

We can inspect the codes with

node -e "import('node:util').then(({styleText}) => console.log(JSON.stringify(styleText('red', 'A ' + styleText('blue', 'B') + ' C'))))"
"\u001b[31mA \u001b[34mB\u001b[39m C\u001b[39m"

The issue is \u001b[39m (def) instead of \u001b[31m (red).

Additional information

No response