mirror of
https://github.com/zebrajr/node.git
synced 2025-12-06 12:20:27 +01:00
util: respect nested formats in styleText
Co-authored-by: Jordan Harband <ljharb@gmail.com> PR-URL: https://github.com/nodejs/node/pull/59098 Fixes: https://github.com/nodejs/node/issues/59035 Reviewed-By: Jordan Harband <ljharb@gmail.com> Reviewed-By: Marco Ippolito <marcoippolito54@gmail.com> Reviewed-By: Moshe Atlow <moshe@atlow.co.il>
This commit is contained in:
parent
6bb08f7f8e
commit
58b5dc3eb2
57
lib/util.js
57
lib/util.js
|
|
@ -25,6 +25,7 @@ const {
|
||||||
ArrayIsArray,
|
ArrayIsArray,
|
||||||
ArrayPrototypePop,
|
ArrayPrototypePop,
|
||||||
ArrayPrototypePush,
|
ArrayPrototypePush,
|
||||||
|
ArrayPrototypeReduce,
|
||||||
Error,
|
Error,
|
||||||
ErrorCaptureStackTrace,
|
ErrorCaptureStackTrace,
|
||||||
FunctionPrototypeBind,
|
FunctionPrototypeBind,
|
||||||
|
|
@ -36,6 +37,8 @@ const {
|
||||||
ObjectSetPrototypeOf,
|
ObjectSetPrototypeOf,
|
||||||
ObjectValues,
|
ObjectValues,
|
||||||
ReflectApply,
|
ReflectApply,
|
||||||
|
RegExp,
|
||||||
|
RegExpPrototypeSymbolReplace,
|
||||||
StringPrototypeToWellFormed,
|
StringPrototypeToWellFormed,
|
||||||
} = primordials;
|
} = primordials;
|
||||||
|
|
||||||
|
|
@ -137,8 +140,7 @@ function styleText(format, text, { validateStream = true, stream = process.stdou
|
||||||
// If the format is not an array, convert it to an array
|
// If the format is not an array, convert it to an array
|
||||||
const formatArray = ArrayIsArray(format) ? format : [format];
|
const formatArray = ArrayIsArray(format) ? format : [format];
|
||||||
|
|
||||||
let left = '';
|
const codes = [];
|
||||||
let right = '';
|
|
||||||
for (const key of formatArray) {
|
for (const key of formatArray) {
|
||||||
if (key === 'none') continue;
|
if (key === 'none') continue;
|
||||||
const formatCodes = inspect.colors[key];
|
const formatCodes = inspect.colors[key];
|
||||||
|
|
@ -147,11 +149,56 @@ function styleText(format, text, { validateStream = true, stream = process.stdou
|
||||||
validateOneOf(key, 'format', ObjectKeys(inspect.colors));
|
validateOneOf(key, 'format', ObjectKeys(inspect.colors));
|
||||||
}
|
}
|
||||||
if (skipColorize) continue;
|
if (skipColorize) continue;
|
||||||
left += escapeStyleCode(formatCodes[0]);
|
ArrayPrototypePush(codes, formatCodes);
|
||||||
right = `${escapeStyleCode(formatCodes[1])}${right}`;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return skipColorize ? text : `${left}${text}${right}`;
|
if (skipColorize) {
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build opening codes
|
||||||
|
let openCodes = '';
|
||||||
|
for (let i = 0; i < codes.length; i++) {
|
||||||
|
openCodes += escapeStyleCode(codes[i][0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process the text to handle nested styles
|
||||||
|
let processedText;
|
||||||
|
if (codes.length > 0) {
|
||||||
|
processedText = ArrayPrototypeReduce(
|
||||||
|
codes,
|
||||||
|
(text, code) => RegExpPrototypeSymbolReplace(
|
||||||
|
// Find the reset code
|
||||||
|
new RegExp(`\\u001b\\[${code[1]}m`, 'g'),
|
||||||
|
text,
|
||||||
|
(match, offset) => {
|
||||||
|
// Check if there's more content after this reset
|
||||||
|
if (offset + match.length < text.length) {
|
||||||
|
if (
|
||||||
|
code[0] === inspect.colors.dim[0] ||
|
||||||
|
code[0] === inspect.colors.bold[0]
|
||||||
|
) {
|
||||||
|
// Dim and bold are not mutually exclusive, so we need to reapply
|
||||||
|
return `${match}${escapeStyleCode(code[0])}`;
|
||||||
|
}
|
||||||
|
return `${escapeStyleCode(code[0])}`;
|
||||||
|
}
|
||||||
|
return match;
|
||||||
|
},
|
||||||
|
),
|
||||||
|
text,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
processedText = text;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build closing codes in reverse order
|
||||||
|
let closeCodes = '';
|
||||||
|
for (let i = codes.length - 1; i >= 0; i--) {
|
||||||
|
closeCodes += escapeStyleCode(codes[i][1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return `${openCodes}${processedText}${closeCodes}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,83 @@ assert.strictEqual(
|
||||||
'\u001b[1m\u001b[31mtest\u001b[39m\u001b[22m',
|
'\u001b[1m\u001b[31mtest\u001b[39m\u001b[22m',
|
||||||
);
|
);
|
||||||
|
|
||||||
|
assert.strictEqual(
|
||||||
|
util.styleText('red',
|
||||||
|
'A' + util.styleText('blue', 'B', { validateStream: false }) + 'C',
|
||||||
|
{ validateStream: false }),
|
||||||
|
'\u001b[31mA\u001b[34mB\u001b[31mC\u001b[39m'
|
||||||
|
);
|
||||||
|
|
||||||
|
assert.strictEqual(
|
||||||
|
util.styleText('red',
|
||||||
|
'red' +
|
||||||
|
util.styleText('blue', 'blue', { validateStream: false }) +
|
||||||
|
'red' +
|
||||||
|
util.styleText('blue', 'blue', { validateStream: false }) +
|
||||||
|
'red',
|
||||||
|
{ validateStream: false }
|
||||||
|
),
|
||||||
|
'\x1B[31mred\x1B[34mblue\x1B[31mred\x1B[34mblue\x1B[31mred\x1B[39m'
|
||||||
|
);
|
||||||
|
|
||||||
|
assert.strictEqual(
|
||||||
|
util.styleText('red',
|
||||||
|
'red' +
|
||||||
|
util.styleText('blue', 'blue', { validateStream: false }) +
|
||||||
|
'red' +
|
||||||
|
util.styleText('red', 'red', { validateStream: false }) +
|
||||||
|
'red' +
|
||||||
|
util.styleText('blue', 'blue', { validateStream: false }),
|
||||||
|
{ validateStream: false }
|
||||||
|
),
|
||||||
|
'\x1b[31mred\x1b[34mblue\x1b[31mred\x1b[31mred\x1b[31mred\x1b[34mblue\x1b[39m\x1b[39m'
|
||||||
|
);
|
||||||
|
|
||||||
|
assert.strictEqual(
|
||||||
|
util.styleText('red',
|
||||||
|
'A' + util.styleText(['bgRed', 'blue'], 'B', { validateStream: false }) +
|
||||||
|
'C', { validateStream: false }),
|
||||||
|
'\x1B[31mA\x1B[41m\x1B[34mB\x1B[31m\x1B[49mC\x1B[39m'
|
||||||
|
);
|
||||||
|
|
||||||
|
assert.strictEqual(
|
||||||
|
util.styleText('dim',
|
||||||
|
'dim' +
|
||||||
|
util.styleText('bold', 'bold', { validateStream: false }) +
|
||||||
|
'dim', { validateStream: false }),
|
||||||
|
'\x1B[2mdim\x1B[1mbold\x1B[22m\x1B[2mdim\x1B[22m'
|
||||||
|
);
|
||||||
|
|
||||||
|
assert.strictEqual(
|
||||||
|
util.styleText('blue',
|
||||||
|
'blue' +
|
||||||
|
util.styleText('red',
|
||||||
|
'red' +
|
||||||
|
util.styleText('green', 'green', { validateStream: false }) +
|
||||||
|
'red', { validateStream: false }) +
|
||||||
|
'blue', { validateStream: false }),
|
||||||
|
'\x1B[34mblue\x1B[31mred\x1B[32mgreen\x1B[31mred\x1B[34mblue\x1B[39m'
|
||||||
|
);
|
||||||
|
|
||||||
|
assert.strictEqual(
|
||||||
|
util.styleText(
|
||||||
|
'red',
|
||||||
|
'red' +
|
||||||
|
util.styleText(
|
||||||
|
'blue',
|
||||||
|
'blue' + util.styleText('red', 'red', {
|
||||||
|
validateStream: false,
|
||||||
|
}) + 'blue',
|
||||||
|
{
|
||||||
|
validateStream: false,
|
||||||
|
}
|
||||||
|
) + 'red', {
|
||||||
|
validateStream: false,
|
||||||
|
}
|
||||||
|
),
|
||||||
|
'\x1b[31mred\x1b[34mblue\x1b[31mred\x1b[34mblue\x1b[31mred\x1b[39m'
|
||||||
|
);
|
||||||
|
|
||||||
assert.strictEqual(
|
assert.strictEqual(
|
||||||
util.styleText(['bold', 'red'], 'test', { validateStream: false }),
|
util.styleText(['bold', 'red'], 'test', { validateStream: false }),
|
||||||
util.styleText(
|
util.styleText(
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user