◐ Shell
clean mode source ↗

util: respect nested formats in styleText · nodejs/node@075d196

@@ -25,6 +25,7 @@ const {

2525

ArrayIsArray,

2626

ArrayPrototypePop,

2727

ArrayPrototypePush,

28+

ArrayPrototypeReduce,

2829

Error,

2930

ErrorCaptureStackTrace,

3031

FunctionPrototypeBind,

@@ -36,6 +37,8 @@ const {

3637

ObjectSetPrototypeOf,

3738

ObjectValues,

3839

ReflectApply,

40+

RegExp,

41+

RegExpPrototypeSymbolReplace,

3942

StringPrototypeToWellFormed,

4043

} = primordials;

4144

@@ -137,8 +140,7 @@ function styleText(format, text, { validateStream = true, stream = process.stdou

137140

// If the format is not an array, convert it to an array

138141

const formatArray = ArrayIsArray(format) ? format : [format];

139142140-

let left = '';

141-

let right = '';

143+

const codes = [];

142144

for (const key of formatArray) {

143145

if (key === 'none') continue;

144146

const formatCodes = inspect.colors[key];

@@ -147,11 +149,56 @@ function styleText(format, text, { validateStream = true, stream = process.stdou

147149

validateOneOf(key, 'format', ObjectKeys(inspect.colors));

148150

}

149151

if (skipColorize) continue;

150-

left += escapeStyleCode(formatCodes[0]);

151-

right = `${escapeStyleCode(formatCodes[1])}${right}`;

152+

ArrayPrototypePush(codes, formatCodes);

152153

}

153154154-

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}`;

155202

}

156203157204

/**