@@ -25,6 +25,7 @@ const {
25
25
ArrayIsArray,
26
26
ArrayPrototypePop,
27
27
ArrayPrototypePush,
28
+ ArrayPrototypeReduce,
28
29
Error,
29
30
ErrorCaptureStackTrace,
30
31
FunctionPrototypeBind,
@@ -36,6 +37,8 @@ const {
36
37
ObjectSetPrototypeOf,
37
38
ObjectValues,
38
39
ReflectApply,
40
+ RegExp,
41
+ RegExpPrototypeSymbolReplace,
39
42
StringPrototypeToWellFormed,
40
43
} = primordials ;
41
44
@@ -137,8 +140,7 @@ function styleText(format, text, { validateStream = true, stream = process.stdou
137
140
// If the format is not an array, convert it to an array
138
141
const formatArray = ArrayIsArray ( format ) ? format : [ format ] ;
139
142
140
- let left = '' ;
141
- let right = '' ;
143
+ const codes = [ ] ;
142
144
for ( const key of formatArray ) {
143
145
if ( key === 'none' ) continue ;
144
146
const formatCodes = inspect . colors [ key ] ;
@@ -147,11 +149,56 @@ function styleText(format, text, { validateStream = true, stream = process.stdou
147
149
validateOneOf ( key , 'format' , ObjectKeys ( inspect . colors ) ) ;
148
150
}
149
151
if ( skipColorize ) continue ;
150
- left += escapeStyleCode ( formatCodes [ 0 ] ) ;
151
- right = `${ escapeStyleCode ( formatCodes [ 1 ] ) } ${ right } ` ;
152
+ ArrayPrototypePush ( codes , formatCodes ) ;
152
153
}
153
154
154
- return skipColorize ? text : `${ left } ${ text } ${ right } ` ;
155
+ if ( skipColorize ) {
156
+ return text ;
157
+ }
158
+
159
+ // Build opening codes
160
+ let openCodes = '' ;
161
+ for ( let i = 0 ; i < codes . length ; i ++ ) {
162
+ openCodes += escapeStyleCode ( codes [ i ] [ 0 ] ) ;
163
+ }
164
+
165
+ // Process the text to handle nested styles
166
+ let processedText ;
167
+ if ( codes . length > 0 ) {
168
+ processedText = ArrayPrototypeReduce (
169
+ codes ,
170
+ ( text , code ) => RegExpPrototypeSymbolReplace (
171
+ // Find the reset code
172
+ new RegExp ( `\\u001b\\[${ code [ 1 ] } m` , 'g' ) ,
173
+ text ,
174
+ ( match , offset ) => {
175
+ // Check if there's more content after this reset
176
+ if ( offset + match . length < text . length ) {
177
+ if (
178
+ code [ 0 ] === inspect . colors . dim [ 0 ] ||
179
+ code [ 0 ] === inspect . colors . bold [ 0 ]
180
+ ) {
181
+ // Dim and bold are not mutually exclusive, so we need to reapply
182
+ return `${ match } ${ escapeStyleCode ( code [ 0 ] ) } ` ;
183
+ }
184
+ return `${ escapeStyleCode ( code [ 0 ] ) } ` ;
185
+ }
186
+ return match ;
187
+ } ,
188
+ ) ,
189
+ text ,
190
+ ) ;
191
+ } else {
192
+ processedText = text ;
193
+ }
194
+
195
+ // Build closing codes in reverse order
196
+ let closeCodes = '' ;
197
+ for ( let i = codes . length - 1 ; i >= 0 ; i -- ) {
198
+ closeCodes += escapeStyleCode ( codes [ i ] [ 1 ] ) ;
199
+ }
200
+
201
+ return `${ openCodes } ${ processedText } ${ closeCodes } ` ;
155
202
}
156
203
157
204
/**
0 commit comments