base.js 3.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. import tty from 'node:tty';
  2. // eslint-disable-next-line no-warning-comments
  3. // TODO: Use a better method when it's added to Node.js (https://github.com/nodejs/node/pull/40240)
  4. // Lots of optionals here to support Deno.
  5. const hasColors = tty?.WriteStream?.prototype?.hasColors?.() ?? false;
  6. const format = (open, close) => {
  7. if (!hasColors) {
  8. return input => input;
  9. }
  10. const openCode = `\u001B[${open}m`;
  11. const closeCode = `\u001B[${close}m`;
  12. return input => {
  13. const string = input + ''; // eslint-disable-line no-implicit-coercion -- This is faster.
  14. let index = string.indexOf(closeCode);
  15. if (index === -1) {
  16. // Note: Intentionally not using string interpolation for performance reasons.
  17. return openCode + string + closeCode;
  18. }
  19. // Handle nested colors.
  20. // We could have done this, but it's too slow (as of Node.js 22).
  21. // return openCode + string.replaceAll(closeCode, (close === 22 ? closeCode : '') + openCode) + closeCode;
  22. let result = openCode;
  23. let lastIndex = 0;
  24. // SGR 22 resets both bold (1) and dim (2). When we encounter a nested
  25. // close for styles that use 22, we need to re-open the outer style.
  26. const reopenOnNestedClose = close === 22;
  27. const replaceCode = (reopenOnNestedClose ? closeCode : '') + openCode;
  28. while (index !== -1) {
  29. result += string.slice(lastIndex, index) + replaceCode;
  30. lastIndex = index + closeCode.length;
  31. index = string.indexOf(closeCode, lastIndex);
  32. }
  33. result += string.slice(lastIndex) + closeCode;
  34. return result;
  35. };
  36. };
  37. export const reset = format(0, 0);
  38. export const bold = format(1, 22);
  39. export const dim = format(2, 22);
  40. export const italic = format(3, 23);
  41. export const underline = format(4, 24);
  42. export const overline = format(53, 55);
  43. export const inverse = format(7, 27);
  44. export const hidden = format(8, 28);
  45. export const strikethrough = format(9, 29);
  46. export const black = format(30, 39);
  47. export const red = format(31, 39);
  48. export const green = format(32, 39);
  49. export const yellow = format(33, 39);
  50. export const blue = format(34, 39);
  51. export const magenta = format(35, 39);
  52. export const cyan = format(36, 39);
  53. export const white = format(37, 39);
  54. export const gray = format(90, 39);
  55. export const bgBlack = format(40, 49);
  56. export const bgRed = format(41, 49);
  57. export const bgGreen = format(42, 49);
  58. export const bgYellow = format(43, 49);
  59. export const bgBlue = format(44, 49);
  60. export const bgMagenta = format(45, 49);
  61. export const bgCyan = format(46, 49);
  62. export const bgWhite = format(47, 49);
  63. export const bgGray = format(100, 49);
  64. export const redBright = format(91, 39);
  65. export const greenBright = format(92, 39);
  66. export const yellowBright = format(93, 39);
  67. export const blueBright = format(94, 39);
  68. export const magentaBright = format(95, 39);
  69. export const cyanBright = format(96, 39);
  70. export const whiteBright = format(97, 39);
  71. export const bgRedBright = format(101, 49);
  72. export const bgGreenBright = format(102, 49);
  73. export const bgYellowBright = format(103, 49);
  74. export const bgBlueBright = format(104, 49);
  75. export const bgMagentaBright = format(105, 49);
  76. export const bgCyanBright = format(106, 49);
  77. export const bgWhiteBright = format(107, 49);