nhb-toolbox
Version:
A versatile collection of smart, efficient, and reusable utility functions, classes and types for everyday development needs.
297 lines (296 loc) • 11.3 kB
JavaScript
;
var _a;
Object.defineProperty(exports, "__esModule", { value: true });
exports.Stylog = exports.LogStyler = void 0;
exports.detectColorSupport = detectColorSupport;
exports.rgbToAnsi = rgbToAnsi;
exports.hexToAnsi = hexToAnsi;
exports.isCSSColor = isCSSColor;
exports.isBGColor = isBGColor;
exports.isTextStyle = isTextStyle;
const convert_1 = require("../colors/convert");
const css_colors_1 = require("../colors/css-colors");
const guards_1 = require("../colors/guards");
const helpers_1 = require("../colors/helpers");
const primitives_1 = require("../guards/primitives");
const specials_1 = require("../guards/specials");
const console_log_1 = require("./console.log");
const constants_1 = require("./constants");
const helpers_2 = require("./helpers");
function detectColorSupport() {
if ('NO_COLOR' in process.env)
return 0;
if ('FORCE_COLOR' in process.env)
return 3;
if (!process.stdout.isTTY)
return 0;
const term = process.env.TERM ?? process.env.COLORTERM ?? '';
if (term === 'dumb')
return 0;
if (/\b256(color)?\b/i.test(term))
return 2;
if (/\btruecolor\b|\b24bit\b/i.test(term))
return 3;
return 1;
}
function rgbToAnsi(r, g, b, isBg = false) {
const open = `\x1b[${isBg ? 48 : 38};2;${r};${g};${b}m`;
const close = `\x1b[${isBg ? 49 : 39}m`;
return [open, close];
}
function hexToAnsi(hex, isBg = false) {
const rgb = ((0, convert_1.convertHexToRgb)(hex).match(/\d+/g) || []).map(parseFloat);
return rgbToAnsi(...rgb, isBg);
}
function isCSSColor(value) {
return value in css_colors_1.CSS_COLORS;
}
function isBGColor(value) {
return value?.startsWith('bg') && isCSSColor(value.slice(2).toLowerCase());
}
function isTextStyle(value) {
return value in constants_1.CSS_TEXT_STYLES || value in constants_1.ANSI_TEXT_STYLES;
}
class LogStyler {
#styles;
constructor(styles = []) {
this.#styles = styles;
}
#applyStyles(...style) {
return createStylogProxy(new _a([...this.#styles, ...style]));
}
style(...style) {
return this.#applyStyles(...style);
}
ansi16(color) {
return this.#applyStyles(constants_1.ANSI_16_COLORS[color], `css-${color}`);
}
toCSS(input, stringify = false) {
const stringified = stringify === true ? JSON.stringify(input) : `${input}`;
const cssList = [];
for (const style of this.#styles) {
if ((0, primitives_1.isString)(style)) {
if (isTextStyle(style)) {
cssList.push(constants_1.CSS_TEXT_STYLES[style]);
}
else if (isBGColor(style)) {
const color = css_colors_1.CSS_COLORS[(0, helpers_2._extractColorName)(style)];
cssList.push(`background: ${color}`);
}
else if (isCSSColor(style)) {
const color = css_colors_1.CSS_COLORS[style];
cssList.push(`color: ${color}`);
}
else if (this.#isValidHexOrRGB(style)) {
if (style.startsWith('bg-')) {
cssList.push(`background: ${style?.replace('bg-', '')}`);
}
else {
cssList.push(`color: ${style}`);
}
}
else if ((0, helpers_2._isCSS16Color)(style)) {
const color = (0, helpers_2._css16ToHex)(style);
const colorValue = style.startsWith('css-bg')
? `background: ${color}`
: `color: ${color}`;
cssList.push(colorValue);
}
}
}
return [`%c${stringified}`, cssList];
}
toANSI(input, stringify = false) {
const stringified = stringify === true ? JSON.stringify(input) : `${input}`;
let openSeq = '', closeSeq = '';
let fgOpenSeq = '', bgOpenSeq = '';
const reopenSequences = new Map();
for (const style of this.#styles) {
if ((0, primitives_1.isString)(style)) {
if (isTextStyle(style)) {
const [open, close] = constants_1.ANSI_TEXT_STYLES[style];
openSeq += open;
closeSeq = close + closeSeq;
reopenSequences.set(close, (reopenSequences.get(close) ?? '') + open);
}
else if (isBGColor(style)) {
const hex = css_colors_1.CSS_COLORS[(0, helpers_2._extractColorName)(style)];
const [open, close] = hexToAnsi(hex, true);
openSeq += open;
closeSeq = close + closeSeq;
bgOpenSeq = open;
}
else if (isCSSColor(style)) {
const hex = css_colors_1.CSS_COLORS[style];
const [open, close] = hexToAnsi(hex, false);
openSeq += open;
closeSeq = close + closeSeq;
fgOpenSeq = open;
}
}
else if ((0, helpers_2._isAnsiSequence)(style)) {
openSeq += style[0];
closeSeq = style[1] + closeSeq;
if (style[1] === '\x1b[49m') {
bgOpenSeq = style[0];
}
else if (style[1] === '\x1b[39m') {
fgOpenSeq = style[0];
}
}
else if ((0, helpers_2._isAnsi16ColorValue)(style)) {
const [open, close] = style.map((s) => `\x1b[${s}m`);
openSeq += open;
closeSeq = close + closeSeq;
if (close === '\x1b[49m') {
bgOpenSeq = open;
}
else if (close === '\x1b[39m') {
fgOpenSeq = open;
}
}
}
if (!detectColorSupport()) {
return stringified;
}
else {
let nestedStr = stringified;
if (nestedStr.includes('\x1b[')) {
if (fgOpenSeq) {
nestedStr = nestedStr.replaceAll('\x1b[39m', `\x1b[39m${fgOpenSeq}`);
}
if (bgOpenSeq) {
nestedStr = nestedStr.replaceAll('\x1b[49m', `\x1b[49m${bgOpenSeq}`);
}
for (const [close, reopen] of reopenSequences) {
nestedStr = nestedStr.replaceAll(close, `${close}${reopen}`);
}
if (openSeq) {
nestedStr = nestedStr.replaceAll('\x1b[0m', `\x1b[0m${openSeq}`);
}
}
return openSeq.concat(nestedStr, closeSeq);
}
}
log(input, stringify = false) {
if ((0, specials_1.isBrowser)()) {
const [fmt, cssList] = this.toCSS(input, stringify);
(0, console_log_1._logToConsole)(fmt, cssList.join(';'));
}
else {
(0, console_log_1._logToConsole)(this.toANSI(input, stringify));
}
}
#isValidHexOrRGB(color) {
const pure = color?.replace('bg-', '');
return (0, guards_1.isHex6)(pure) || (0, guards_1.isRGB)(pure);
}
#sanitizeHex(code) {
return code?.trim()?.startsWith('#') ? code?.trim() : `#${code?.trim()}`;
}
#handleHex(code, isBg = false) {
const sanitized = this.#sanitizeHex(code);
if (!(0, guards_1.isHex6)(sanitized)) {
return this.#applyStyles();
}
const ansi = hexToAnsi(sanitized, isBg);
return this.#applyStyles(isBg ? `bg-${sanitized}` : sanitized, ansi);
}
hex(code) {
return this.#handleHex(code, false);
}
bgHex(code) {
return this.#handleHex(code, true);
}
#extractColorValues(code) {
const trimmed = code?.trim();
return (trimmed?.match(/[\d.]+%?/g) || []).map(parseFloat);
}
#isValidRGB(...value) {
return value.every(helpers_1._isValidRGBComponent);
}
#handleRGB(code, green, blue, isBg = false) {
if ((0, primitives_1.isString)(code)) {
const rgb = this.#extractColorValues(code);
if (this.#isValidRGB(...rgb)) {
return this.#applyStyles(rgbToAnsi(...rgb, isBg), isBg
? `bg-rgb(${rgb[0]}, ${rgb[1]}, ${rgb[2]})`
: `rgb(${rgb[0]}, ${rgb[1]}, ${rgb[2]})`);
}
else {
return this.#applyStyles();
}
}
else if ((0, primitives_1.isNumber)(code) && (0, primitives_1.isNumber)(green) && (0, primitives_1.isNumber)(blue)) {
if (this.#isValidRGB(code, green, blue)) {
return this.#applyStyles(rgbToAnsi(code, green, blue, isBg), isBg
? `bg-rgb(${code}, ${green}, ${blue})`
: `rgb(${code}, ${green}, ${blue})`);
}
else {
return this.#applyStyles();
}
}
else {
return this.#applyStyles();
}
}
rgb(code, green, blue) {
return this.#handleRGB(code, green, blue, false);
}
bgRGB(code, green, blue) {
return this.#handleRGB(code, green, blue, true);
}
#isValidHSL(h, s, l) {
return (0, helpers_1._isValidHue)(h) && (0, helpers_1._isValidPercentage)(s) && (0, helpers_1._isValidPercentage)(l);
}
#handleHSL(code, saturation, lightness, isBg = false) {
if ((0, primitives_1.isString)(code)) {
const hsl = this.#extractColorValues(code);
if (this.#isValidHSL(...hsl)) {
return this.#handleRGB((0, convert_1.convertHslToRgb)(...hsl), undefined, undefined, isBg);
}
else {
return this.#applyStyles();
}
}
else if ((0, primitives_1.isNumber)(code) && (0, primitives_1.isNumber)(saturation) && (0, primitives_1.isNumber)(lightness)) {
if (this.#isValidHSL(code, saturation, lightness)) {
return this.#handleRGB((0, convert_1.convertHslToRgb)(code, saturation, lightness), undefined, undefined, isBg);
}
else {
return this.#applyStyles();
}
}
else {
return this.#applyStyles();
}
}
hsl(code, saturation, lightness) {
return this.#handleHSL(code, saturation, lightness, false);
}
bgHSL(code, saturation, lightness) {
return this.#handleHSL(code, saturation, lightness, true);
}
}
exports.LogStyler = LogStyler;
_a = LogStyler;
function createStylogProxy(styler) {
return new Proxy(styler, {
get(target, prop) {
if (prop in target) {
const value = target[prop];
if (typeof value === 'function') {
return value.bind(target);
}
else {
return value;
}
}
if (isCSSColor(prop) || isBGColor(prop) || isTextStyle(prop)) {
return createStylogProxy(target.style(prop));
}
},
});
}
exports.Stylog = createStylogProxy(new LogStyler());