UNPKG

@prostojs/dye

Version:

Easy and light console styling tool

418 lines (416 loc) 14.5 kB
//#region src/index.ts const DyeColors = [ "black", "red", "green", "yellow", "blue", "magenta", "cyan", "white" ]; const DyeGrayscale = [ "gray01", "gray02", "gray03", "gray04", "gray05", "gray06", "gray07", "gray08", "gray09", "gray10", "gray11", "gray12", "gray13", "gray14", "gray15", "gray16", "gray17", "gray18", "gray19", "gray20", "gray21", "gray22" ]; const DyeModifier = [ "bold", "dim", "italic", "underscore", "inverse", "hidden", "crossed" ]; var Codes = function(Codes$1) { Codes$1[Codes$1["RESET"] = 0] = "RESET"; Codes$1[Codes$1["BOLD"] = 1] = "BOLD"; Codes$1[Codes$1["DIM"] = 2] = "DIM"; Codes$1[Codes$1["ITALIC"] = 3] = "ITALIC"; Codes$1[Codes$1["UNDERSCORE"] = 4] = "UNDERSCORE"; Codes$1[Codes$1["INVERSE"] = 7] = "INVERSE"; Codes$1[Codes$1["HIDDEN"] = 8] = "HIDDEN"; Codes$1[Codes$1["CROSSED"] = 9] = "CROSSED"; Codes$1[Codes$1["BOLD_OFF"] = 22] = "BOLD_OFF"; Codes$1[Codes$1["DIM_OFF"] = 22] = "DIM_OFF"; Codes$1[Codes$1["ITALIC_OFF"] = 23] = "ITALIC_OFF"; Codes$1[Codes$1["UNDERSCORE_OFF"] = 24] = "UNDERSCORE_OFF"; Codes$1[Codes$1["BLINK_SLOW_OFF"] = 25] = "BLINK_SLOW_OFF"; Codes$1[Codes$1["BLINK_RAPID_OFF"] = 26] = "BLINK_RAPID_OFF"; Codes$1[Codes$1["INVERSE_OFF"] = 27] = "INVERSE_OFF"; Codes$1[Codes$1["REVEAL"] = 28] = "REVEAL"; Codes$1[Codes$1["CROSSED_OFF"] = 29] = "CROSSED_OFF"; Codes$1[Codes$1["BLACK"] = 30] = "BLACK"; Codes$1[Codes$1["RED"] = 31] = "RED"; Codes$1[Codes$1["GREEN"] = 32] = "GREEN"; Codes$1[Codes$1["YELLOW"] = 33] = "YELLOW"; Codes$1[Codes$1["BLUE"] = 34] = "BLUE"; Codes$1[Codes$1["MAGENTA"] = 35] = "MAGENTA"; Codes$1[Codes$1["CYAN"] = 36] = "CYAN"; Codes$1[Codes$1["WHITE"] = 37] = "WHITE"; Codes$1[Codes$1["COLORS"] = 38] = "COLORS"; Codes$1[Codes$1["COLOR_OFF"] = 39] = "COLOR_OFF"; Codes$1[Codes$1["BG_BLACK"] = 40] = "BG_BLACK"; Codes$1[Codes$1["BG_RED"] = 41] = "BG_RED"; Codes$1[Codes$1["BG_GREEN"] = 42] = "BG_GREEN"; Codes$1[Codes$1["BG_YELLOW"] = 43] = "BG_YELLOW"; Codes$1[Codes$1["BG_BLUE"] = 44] = "BG_BLUE"; Codes$1[Codes$1["BG_MAGENTA"] = 45] = "BG_MAGENTA"; Codes$1[Codes$1["BG_CYAN"] = 46] = "BG_CYAN"; Codes$1[Codes$1["BG_WHITE"] = 47] = "BG_WHITE"; Codes$1[Codes$1["BG_COLORS"] = 48] = "BG_COLORS"; Codes$1[Codes$1["BG_COLOR_OFF"] = 49] = "BG_COLOR_OFF"; Codes$1[Codes$1["GRAY01"] = 233] = "GRAY01"; Codes$1[Codes$1["GRAY02"] = 234] = "GRAY02"; Codes$1[Codes$1["GRAY03"] = 235] = "GRAY03"; Codes$1[Codes$1["GRAY04"] = 236] = "GRAY04"; Codes$1[Codes$1["GRAY05"] = 237] = "GRAY05"; Codes$1[Codes$1["GRAY06"] = 238] = "GRAY06"; Codes$1[Codes$1["GRAY07"] = 239] = "GRAY07"; Codes$1[Codes$1["GRAY08"] = 240] = "GRAY08"; Codes$1[Codes$1["GRAY09"] = 241] = "GRAY09"; Codes$1[Codes$1["GRAY10"] = 242] = "GRAY10"; Codes$1[Codes$1["GRAY11"] = 243] = "GRAY11"; Codes$1[Codes$1["GRAY12"] = 244] = "GRAY12"; Codes$1[Codes$1["GRAY13"] = 245] = "GRAY13"; Codes$1[Codes$1["GRAY14"] = 246] = "GRAY14"; Codes$1[Codes$1["GRAY15"] = 247] = "GRAY15"; Codes$1[Codes$1["GRAY16"] = 248] = "GRAY16"; Codes$1[Codes$1["GRAY17"] = 249] = "GRAY17"; Codes$1[Codes$1["GRAY18"] = 250] = "GRAY18"; Codes$1[Codes$1["GRAY19"] = 251] = "GRAY19"; Codes$1[Codes$1["GRAY20"] = 252] = "GRAY20"; Codes$1[Codes$1["GRAY21"] = 253] = "GRAY21"; Codes$1[Codes$1["GRAY22"] = 254] = "GRAY22"; Codes$1[Codes$1["BLACK_BRIGHT"] = 90] = "BLACK_BRIGHT"; Codes$1[Codes$1["RED_BRIGHT"] = 91] = "RED_BRIGHT"; Codes$1[Codes$1["GREEN_BRIGHT"] = 92] = "GREEN_BRIGHT"; Codes$1[Codes$1["YELLOW_BRIGHT"] = 93] = "YELLOW_BRIGHT"; Codes$1[Codes$1["BLUE_BRIGHT"] = 94] = "BLUE_BRIGHT"; Codes$1[Codes$1["MAGENTA_BRIGHT"] = 95] = "MAGENTA_BRIGHT"; Codes$1[Codes$1["CYAN_BRIGHT"] = 96] = "CYAN_BRIGHT"; Codes$1[Codes$1["WHITE_BRIGHT"] = 97] = "WHITE_BRIGHT"; Codes$1[Codes$1["BG_BLACK_BRIGHT"] = 100] = "BG_BLACK_BRIGHT"; Codes$1[Codes$1["BG_RED_BRIGHT"] = 101] = "BG_RED_BRIGHT"; Codes$1[Codes$1["BG_GREEN_BRIGHT"] = 102] = "BG_GREEN_BRIGHT"; Codes$1[Codes$1["BG_YELLOW_BRIGHT"] = 103] = "BG_YELLOW_BRIGHT"; Codes$1[Codes$1["BG_BLUE_BRIGHT"] = 104] = "BG_BLUE_BRIGHT"; Codes$1[Codes$1["BG_MAGENTA_BRIGHT"] = 105] = "BG_MAGENTA_BRIGHT"; Codes$1[Codes$1["BG_CYAN_BRIGHT"] = 106] = "BG_CYAN_BRIGHT"; Codes$1[Codes$1["BG_WHITE_BRIGHT"] = 107] = "BG_WHITE_BRIGHT"; return Codes$1; }(Codes || {}); const BG_OFFSET = 10; const plain = (...n) => `\u001B[${n.join(";")}m`; const gray = (n) => `\u001B[38;5;${n}m`; const bgGray = (n) => `\u001B[48;5;${n}m`; const rgb256 = (r, g, b, bg = false) => `\u001B[${38 + Number(bg) * BG_OFFSET};5;${16 + r * 36 + g * 6 + b}m`; const tcRGB = (r, g, b, bg = false) => `\u001B[${38 + Number(bg) * BG_OFFSET};2;${r};${g};${b}m`; const colors = { "black": Codes.BLACK, "red": Codes.RED, "green": Codes.GREEN, "yellow": Codes.YELLOW, "blue": Codes.BLUE, "magenta": Codes.MAGENTA, "cyan": Codes.CYAN, "white": Codes.WHITE, "black-bright": Codes.BLACK_BRIGHT, "red-bright": Codes.RED_BRIGHT, "green-bright": Codes.GREEN_BRIGHT, "yellow-bright": Codes.YELLOW_BRIGHT, "blue-bright": Codes.BLUE_BRIGHT, "magenta-bright": Codes.MAGENTA_BRIGHT, "cyan-bright": Codes.CYAN_BRIGHT, "white-bright": Codes.WHITE_BRIGHT }; const grayColors = { gray01: Codes.GRAY01, gray02: Codes.GRAY02, gray03: Codes.GRAY03, gray04: Codes.GRAY04, gray05: Codes.GRAY05, gray06: Codes.GRAY06, gray07: Codes.GRAY07, gray08: Codes.GRAY08, gray09: Codes.GRAY09, gray10: Codes.GRAY10, gray11: Codes.GRAY11, gray12: Codes.GRAY12, gray13: Codes.GRAY13, gray14: Codes.GRAY14, gray15: Codes.GRAY15, gray16: Codes.GRAY16, gray17: Codes.GRAY17, gray18: Codes.GRAY18, gray19: Codes.GRAY19, gray20: Codes.GRAY20, gray21: Codes.GRAY21, gray22: Codes.GRAY22 }; const bgGrayColors = { "bg-gray01": Codes.GRAY01, "bg-gray02": Codes.GRAY02, "bg-gray03": Codes.GRAY03, "bg-gray04": Codes.GRAY04, "bg-gray05": Codes.GRAY05, "bg-gray06": Codes.GRAY06, "bg-gray07": Codes.GRAY07, "bg-gray08": Codes.GRAY08, "bg-gray09": Codes.GRAY09, "bg-gray10": Codes.GRAY10, "bg-gray11": Codes.GRAY11, "bg-gray12": Codes.GRAY12, "bg-gray13": Codes.GRAY13, "bg-gray14": Codes.GRAY14, "bg-gray15": Codes.GRAY15, "bg-gray16": Codes.GRAY16, "bg-gray17": Codes.GRAY17, "bg-gray18": Codes.GRAY18, "bg-gray19": Codes.GRAY19, "bg-gray20": Codes.GRAY20, "bg-gray21": Codes.GRAY21, "bg-gray22": Codes.GRAY22 }; const bgColors = { "bg-black": Codes.BG_BLACK, "bg-red": Codes.BG_RED, "bg-green": Codes.BG_GREEN, "bg-yellow": Codes.BG_YELLOW, "bg-blue": Codes.BG_BLUE, "bg-magenta": Codes.BG_MAGENTA, "bg-cyan": Codes.BG_CYAN, "bg-white": Codes.BG_WHITE, "bg-black-bright": Codes.BG_BLACK_BRIGHT, "bg-red-bright": Codes.BG_RED_BRIGHT, "bg-green-bright": Codes.BG_GREEN_BRIGHT, "bg-yellow-bright": Codes.BG_YELLOW_BRIGHT, "bg-blue-bright": Codes.BG_BLUE_BRIGHT, "bg-magenta-bright": Codes.BG_MAGENTA_BRIGHT, "bg-cyan-bright": Codes.BG_CYAN_BRIGHT, "bg-white-bright": Codes.BG_WHITE_BRIGHT }; const modifiers = { bold: Codes.BOLD, dim: Codes.DIM, italic: Codes.ITALIC, underscore: Codes.UNDERSCORE, inverse: Codes.INVERSE, hidden: Codes.HIDDEN, crossed: Codes.CROSSED }; const modifiersClose = { "color": Codes.COLOR_OFF, "bg-color": Codes.BG_COLOR_OFF, "bold": Codes.BOLD_OFF, "dim": Codes.DIM_OFF, "italic": Codes.ITALIC_OFF, "underscore": Codes.UNDERSCORE_OFF, "inverse": Codes.INVERSE_OFF, "hidden": Codes.REVEAL, "crossed": Codes.CROSSED_OFF }; const dye = (...args) => { const openStack = []; const openColorsStack = []; const openBgColorsStack = []; const openModifiersStack = []; const closeModifiers = {}; if (args.length > 0) for (const c of args) if (c.indexOf(",") > 0 || c.includes("#")) { let bg = false; if (c.includes("#")) { if (c.startsWith("bg")) bg = true; let hex = c.split("#").pop(); if (!/^([0-9a-f]{3}|[0-9a-f]{6})$/iu.test(hex)) throw new Error(`[Dye] Wrong hex "#${hex}".`); if (hex.length === 3) hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2]; const r = Number.parseInt(hex.slice(0, 2), 16); const g = Number.parseInt(hex.slice(2, 4), 16); const b = Number.parseInt(hex.slice(4, 6), 16); openStack.push(tcRGB(r, g, b, bg)); } else { let mode256 = false; let [r, g, b] = c.split(","); if (r.startsWith("bg")) { bg = true; r = r.slice(2); } if (r.startsWith("*")) { mode256 = true; r = r.slice(1); } if (mode256) { r = checkRGBNumber(r.trim(), "r", 5); g = checkRGBNumber(g, "g", 5); b = checkRGBNumber(b, "b", 5); openStack.push(rgb256(r, g, b, bg)); } else { r = checkRGBNumber(r.trim(), "r", 255); g = checkRGBNumber(g, "g", 255); b = checkRGBNumber(b, "b", 255); openStack.push(tcRGB(r, g, b, bg)); } } if (bg) { closeModifiers[Codes.BG_COLOR_OFF] = true; openBgColorsStack.push(openStack[openStack.length - 1]); } else { closeModifiers[Codes.COLOR_OFF] = true; openColorsStack.push(openStack[openStack.length - 1]); } } else if (colors[c]) { openStack.push(colors[c]); closeModifiers[Codes.COLOR_OFF] = true; openColorsStack.push(openStack[openStack.length - 1]); } else if (bgColors[c]) { openStack.push(bgColors[c]); closeModifiers[Codes.BG_COLOR_OFF] = true; openBgColorsStack.push(openStack[openStack.length - 1]); } else if (modifiers[c]) { openStack.push(modifiers[c]); closeModifiers[modifiersClose[c]] = true; openModifiersStack.push(openStack[openStack.length - 1]); } else if (grayColors[c]) { openStack.push(gray(grayColors[c])); closeModifiers[Codes.COLOR_OFF] = true; openColorsStack.push(openStack[openStack.length - 1]); } else if (bgGrayColors[c]) { openStack.push(bgGray(bgGrayColors[c])); closeModifiers[Codes.BG_COLOR_OFF] = true; openBgColorsStack.push(openStack[openStack.length - 1]); } else throw new Error(`[Dye] Color or modifier "${c}" is not supported.`); function collapseStack(stack) { let modStack = []; let result = ""; for (const modifier of stack) if (typeof modifier === "number") modStack.push(modifier); else { if (modStack.length > 0) { result += plain(...modStack); modStack = []; } result += modifier; } if (modStack.length > 0) { result += plain(...modStack); modStack = []; } return result; } const open = collapseStack(openStack); const openColors = collapseStack(openColorsStack); const openBgColors = collapseStack(openBgColorsStack); const openModifiers = collapseStack(openModifiersStack); const closingCodes = Object.keys(closeModifiers); const close = closingCodes.length > 0 ? plain(...closingCodes) : ""; return getStylist(open, close, "", "", { openColors, openBgColors, openModifiers }); }; dye.strip = (coloredText) => coloredText.replace(/\x1B\[[^m]+m/gu, ""); dye.reset = plain(Codes.RESET); dye.bold_off = plain(Codes.BOLD_OFF); dye.dim_off = plain(Codes.DIM_OFF); dye.italic_off = plain(Codes.ITALIC_OFF); dye.underscore_off = plain(Codes.UNDERSCORE_OFF); dye.blink_slow_off = plain(Codes.BLINK_SLOW_OFF); dye.blink_rapid_off = plain(Codes.BLINK_RAPID_OFF); dye.inverse_off = plain(Codes.INVERSE_OFF); dye.reveal = plain(Codes.REVEAL); dye.crossed_off = plain(Codes.CROSSED_OFF); function getStylist(open, close, prefix, suffix, parts, format) { const resetOpen = dye.reset + open; const getPrefix = (...texts) => { const v = typeof prefix === "string" ? prefix : prefix(...texts); return v ? open + v : ""; }; const getSuffix = (...texts) => { const v = typeof suffix === "string" ? suffix : suffix(...texts); return (v ? open + v : "") + close; }; const formatDefault = (...texts) => texts.map(String).join(" "); const stylist = (...texts) => { const p = getPrefix(...texts) || ""; const s = getSuffix(...texts) || ""; const text = format ? format(...texts) : formatDefault(...texts); return `${p}${open}${sanitizeString(text, parts)}${s}`; }; stylist.open = open; stylist.close = close; stylist.format = (cb) => getStylist(open, close, prefix, suffix, parts, cb); stylist.prefix = (v) => getStylist(open, close, v, suffix, parts, format); stylist.suffix = (v) => getStylist(open, close, prefix, v, parts, format); stylist.attachConsole = (...args) => { const consoleInterface = args[1] || console; let consoleMethod; if (typeof args[0] === "string" || args[0] === undefined) consoleMethod = consoleInterface[args[0] || "log"]; else if (typeof args[0] === "function") consoleMethod = args[0]; let enabled = true; const dyeConsole = (...consoleArgs) => { if (enabled) { const p = getPrefix(...consoleArgs); const s = getSuffix(...consoleArgs); const start = p ? dye.reset + p : ""; const end = s === close ? dye.reset : dye.reset + s; if (format) consoleMethod(start + resetOpen + format(...consoleArgs) + end); else { let first = ""; if (typeof consoleArgs[0] === "string" || typeof consoleArgs[0] === "number") first = resetOpen + sanitizeString(String(consoleArgs.shift()), parts); let last = ""; if (typeof consoleArgs[consoleArgs.length - 1] === "string") last = resetOpen + sanitizeString(consoleArgs.pop(), parts); const newArgs = consoleArgs.flatMap((a) => { if (typeof a === "string") return resetOpen + sanitizeString(a, parts); else if (typeof a === "number") return resetOpen + a.toString(); else return [dye.reset, a]; }); if (newArgs.length > 0) consoleMethod(...[ start + first, ...newArgs, last + end ].filter((e) => typeof e !== "string" || !!e)); else consoleMethod(start + first + last + end); } } }; dyeConsole.enable = (v = true) => enabled = v; dyeConsole.disable = () => enabled = false; dyeConsole.asStylist = () => stylist; return dyeConsole; }; return stylist; } function sanitizeString(source, parts) { let result = source; if (parts.openColors) result = result.replace(/(\x1B\[[0-9;]*39[0-9;]*m)/gu, `$1${parts.openColors}`); if (parts.openBgColors) result = result.replace(/(\x1B\[[0-9;]*49[0-9;]*m)/gu, `$1${parts.openBgColors}`); if (parts.openModifiers) result = result.replace(/(\x1B\[(?:22|23|24)m)/gu, `$1${parts.openModifiers}`); return result; } function checkRGBNumber(n, component, limit = 255) { const _n = Number(n); if (Number.isNaN(_n)) throw new TypeError(`[Dye] Color component "${component}" must be a number. Received "${n}".`); if (_n > limit) throw new Error(`[Dye] Color component "${component}" must be less than ${limit + 1}. Received "${n}".`); return _n; } //#endregion export { DyeColors, DyeGrayscale, DyeModifier, dye };