import * as tty from 'node:tty'; const { env = {}, argv = [], platform = "" } = typeof process === "undefined" ? {} : process; const isDisabled = "NO_COLOR" in env || argv.includes("--no-color"); const isForced = "FORCE_COLOR" in env || argv.includes("--color"); const isWindows = platform === "win32"; const isDumbTerminal = env.TERM === "dumb"; const isCompatibleTerminal = tty && tty.isatty && tty.isatty(1) && env.TERM && !isDumbTerminal; const isCI = "CI" in env && ("GITHUB_ACTIONS" in env || "GITLAB_CI" in env || "CIRCLECI" in env); const isColorSupported = !isDisabled && (isForced || isWindows && !isDumbTerminal || isCompatibleTerminal || isCI); function replaceClose(index, string, close, replace, head = string.slice(0, Math.max(0, index)) + replace, tail = string.slice(Math.max(0, index + close.length)), next = tail.indexOf(close)) { return head + (next < 0 ? tail : replaceClose(next, tail, close, replace)); } function clearBleed(index, string, open, close, replace) { return index < 0 ? open + string + close : open + replaceClose(index, string, close, replace) + close; } function filterEmpty(open, close, replace = open, at = open.length + 1) { return (string) => string || !(string === "" || string === void 0) ? clearBleed( ("" + string).indexOf(close, at), string, open, close, replace ) : ""; } function init(open, close, replace) { return filterEmpty(`\x1B[${open}m`, `\x1B[${close}m`, replace); } const colorDefs = { reset: init(0, 0), bold: init(1, 22, "\x1B[22m\x1B[1m"), dim: init(2, 22, "\x1B[22m\x1B[2m"), italic: init(3, 23), underline: init(4, 24), inverse: init(7, 27), hidden: init(8, 28), strikethrough: init(9, 29), black: init(30, 39), red: init(31, 39), green: init(32, 39), yellow: init(33, 39), blue: init(34, 39), magenta: init(35, 39), cyan: init(36, 39), white: init(37, 39), gray: init(90, 39), bgBlack: init(40, 49), bgRed: init(41, 49), bgGreen: init(42, 49), bgYellow: init(43, 49), bgBlue: init(44, 49), bgMagenta: init(45, 49), bgCyan: init(46, 49), bgWhite: init(47, 49), blackBright: init(90, 39), redBright: init(91, 39), greenBright: init(92, 39), yellowBright: init(93, 39), blueBright: init(94, 39), magentaBright: init(95, 39), cyanBright: init(96, 39), whiteBright: init(97, 39), bgBlackBright: init(100, 49), bgRedBright: init(101, 49), bgGreenBright: init(102, 49), bgYellowBright: init(103, 49), bgBlueBright: init(104, 49), bgMagentaBright: init(105, 49), bgCyanBright: init(106, 49), bgWhiteBright: init(107, 49) }; function createColors(useColor = isColorSupported) { return useColor ? colorDefs : Object.fromEntries(Object.keys(colorDefs).map((key) => [key, String])); } const colors = createColors(); function getColor(color, fallback = "reset") { return colors[color] || colors[fallback]; } function colorize(color, text) { return getColor(color)(text); } const ansiRegex = [ "[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]+)*|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)", "(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-nq-uy=><~]))" ].join("|"); function stripAnsi(text) { return text.replace(new RegExp(ansiRegex, "g"), ""); } function centerAlign(str, len, space = " ") { const free = len - str.length; if (free <= 0) { return str; } const freeLeft = Math.floor(free / 2); let _str = ""; for (let i = 0; i < len; i++) { _str += i < freeLeft || i >= freeLeft + str.length ? space : str[i - freeLeft]; } return _str; } function rightAlign(str, len, space = " ") { const free = len - str.length; if (free <= 0) { return str; } let _str = ""; for (let i = 0; i < len; i++) { _str += i < free ? space : str[i - free]; } return _str; } function leftAlign(str, len, space = " ") { let _str = ""; for (let i = 0; i < len; i++) { _str += i < str.length ? str[i] : space; } return _str; } function align(alignment, str, len, space = " ") { switch (alignment) { case "left": { return leftAlign(str, len, space); } case "right": { return rightAlign(str, len, space); } case "center": { return centerAlign(str, len, space); } default: { return str; } } } const boxStylePresets = { solid: { tl: "\u250C", tr: "\u2510", bl: "\u2514", br: "\u2518", h: "\u2500", v: "\u2502" }, double: { tl: "\u2554", tr: "\u2557", bl: "\u255A", br: "\u255D", h: "\u2550", v: "\u2551" }, doubleSingle: { tl: "\u2553", tr: "\u2556", bl: "\u2559", br: "\u255C", h: "\u2500", v: "\u2551" }, doubleSingleRounded: { tl: "\u256D", tr: "\u256E", bl: "\u2570", br: "\u256F", h: "\u2500", v: "\u2551" }, singleThick: { tl: "\u250F", tr: "\u2513", bl: "\u2517", br: "\u251B", h: "\u2501", v: "\u2503" }, singleDouble: { tl: "\u2552", tr: "\u2555", bl: "\u2558", br: "\u255B", h: "\u2550", v: "\u2502" }, singleDoubleRounded: { tl: "\u256D", tr: "\u256E", bl: "\u2570", br: "\u256F", h: "\u2550", v: "\u2502" }, rounded: { tl: "\u256D", tr: "\u256E", bl: "\u2570", br: "\u256F", h: "\u2500", v: "\u2502" } }; const defaultStyle = { borderColor: "white", borderStyle: "rounded", valign: "center", padding: 2, marginLeft: 1, marginTop: 1, marginBottom: 1 }; function box(text, _opts = {}) { const opts = { ..._opts, style: { ...defaultStyle, ..._opts.style } }; const textLines = text.split("\n"); const boxLines = []; const _color = getColor(opts.style.borderColor); const borderStyle = { ...typeof opts.style.borderStyle === "string" ? boxStylePresets[opts.style.borderStyle] || boxStylePresets.solid : opts.style.borderStyle }; if (_color) { for (const key in borderStyle) { borderStyle[key] = _color( borderStyle[key] ); } } const paddingOffset = opts.style.padding % 2 === 0 ? opts.style.padding : opts.style.padding + 1; const height = textLines.length + paddingOffset; const width = Math.max(...textLines.map((line) => line.length)) + paddingOffset; const widthOffset = width + paddingOffset; const leftSpace = opts.style.marginLeft > 0 ? " ".repeat(opts.style.marginLeft) : ""; if (opts.style.marginTop > 0) { boxLines.push("".repeat(opts.style.marginTop)); } if (opts.title) { const left = borderStyle.h.repeat( Math.floor((width - stripAnsi(opts.title).length) / 2) ); const right = borderStyle.h.repeat( width - stripAnsi(opts.title).length - stripAnsi(left).length + paddingOffset ); boxLines.push( `${leftSpace}${borderStyle.tl}${left}${opts.title}${right}${borderStyle.tr}` ); } else { boxLines.push( `${leftSpace}${borderStyle.tl}${borderStyle.h.repeat(widthOffset)}${borderStyle.tr}` ); } const valignOffset = opts.style.valign === "center" ? Math.floor((height - textLines.length) / 2) : opts.style.valign === "top" ? height - textLines.length - paddingOffset : height - textLines.length; for (let i = 0; i < height; i++) { if (i < valignOffset || i >= valignOffset + textLines.length) { boxLines.push( `${leftSpace}${borderStyle.v}${" ".repeat(widthOffset)}${borderStyle.v}` ); } else { const line = textLines[i - valignOffset]; const left = " ".repeat(paddingOffset); const right = " ".repeat(width - stripAnsi(line).length); boxLines.push( `${leftSpace}${borderStyle.v}${left}${line}${right}${borderStyle.v}` ); } } boxLines.push( `${leftSpace}${borderStyle.bl}${borderStyle.h.repeat(widthOffset)}${borderStyle.br}` ); if (opts.style.marginBottom > 0) { boxLines.push("".repeat(opts.style.marginBottom)); } return boxLines.join("\n"); } export { align, box, centerAlign, colorize, colors, getColor, leftAlign, rightAlign, stripAnsi };