UNPKG

@trap_stevo/filetide

Version:

Revolutionizing real-time file transfer with seamless, instant communication across any device. Deliver files instantly, regardless of platform, and experience unparalleled speed and control in managing transfers. Elevate your file-sharing capabilities wi

349 lines (348 loc) 10.6 kB
"use strict"; const chalk = require("chalk"); class ConsoleTable { constructor(options = {}) { this.options = { padding: 1, headerAlign: "center", cellAlign: "left", borderStyle: "solid", headerColor: null, borderColor: null, cellColor: (content, columnName, rowData) => content, columnOrder: null, columnNames: {}, title: "", tableNumber: null, gradient: { title: null, header: null, border: null, cell: null }, ...options }; this.borderChars = this.getBorderChars(this.options.borderStyle); } getBorderChars(style) { const styles = { solid: { topLeft: "┌", topRight: "┐", bottomLeft: "└", bottomRight: "┘", horizontal: "─", vertical: "│", topJoin: "┬", bottomJoin: "┴", leftJoin: "├", rightJoin: "┤", center: "┼" }, double: { topLeft: "╔", topRight: "╗", bottomLeft: "╚", bottomRight: "╝", horizontal: "═", vertical: "║", topJoin: "╦", bottomJoin: "╩", leftJoin: "╠", rightJoin: "╣", center: "╬" }, round: { topLeft: "╭", topRight: "╮", bottomLeft: "╰", bottomRight: "╯", horizontal: "─", vertical: "│", topJoin: "┬", bottomJoin: "┴", leftJoin: "├", rightJoin: "┤", center: "┼" }, bold: { topLeft: "┏", topRight: "┓", bottomLeft: "┗", bottomRight: "┛", horizontal: "━", vertical: "┃", topJoin: "┳", bottomJoin: "┻", leftJoin: "┣", rightJoin: "┫", center: "╋" } }; return styles[style] || styles["solid"]; } setData(data) { if (Array.isArray(data)) { this.data = data; } else if (typeof data === "object") { this.data = Object.values(data); } else { throw new Error("Array or an object only."); } this.extractColumns(); this.calculateColumnWidths(); } extractColumns() { if (this.options.columnOrder && Array.isArray(this.options.columnOrder)) { this.columns = this.options.columnOrder; } else { const columnsSet = new Set(); this.data.forEach(item => { Object.keys(item).forEach(key => columnsSet.add(key)); }); this.columns = Array.from(columnsSet); } } calculateColumnWidths() { const { padding } = this.options; this.columnWidths = {}; this.totalWidth = 0; this.columns.forEach(column => { const headerName = this.options.columnNames[column] || column; let maxWidth = String(headerName).length; this.data.forEach(item => { const cellContent = item[column] !== undefined ? String(item[column]) : ""; maxWidth = Math.max(maxWidth, cellContent.length); }); const columnWidth = maxWidth + padding * 2; this.columnWidths[column] = columnWidth; this.totalWidth += columnWidth; }); this.totalWidth += this.columns.length + 1; } alignText(text, width, align) { const { padding } = this.options; const textLength = text.length; let totalPadding = width - textLength; let leftPadding = " ".repeat(padding); let rightPadding = " ".repeat(padding); if (totalPadding < padding * 2) { leftPadding = ""; rightPadding = ""; } else { totalPadding -= padding * 2; if (align === "left") { rightPadding += " ".repeat(totalPadding); } else if (align === "right") { leftPadding += " ".repeat(totalPadding); } else { const half = Math.floor(totalPadding / 2); leftPadding += " ".repeat(half); rightPadding += " ".repeat(totalPadding - half); } } return leftPadding + text + rightPadding; } generateGradientText(text, startColor, endColor) { const length = text.length; const startRGB = this.hexToRgb(startColor); const endRGB = this.hexToRgb(endColor); let gradientText = ""; for (let i = 0; i < length; i++) { const ratio = i / (length - 1 || 1); const color = { r: Math.round(startRGB.r + ratio * (endRGB.r - startRGB.r)), g: Math.round(startRGB.g + ratio * (endRGB.g - startRGB.g)), b: Math.round(startRGB.b + ratio * (endRGB.b - startRGB.b)) }; gradientText += chalk.rgb(color.r, color.g, color.b)(text[i]); } return gradientText; } hexToRgb(hex) { const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); return result ? { r: parseInt(result[1], 16), g: parseInt(result[2], 16), b: parseInt(result[3], 16) } : null; } generateBorder(type) { const { columns, columnWidths } = this; let { horizontal, vertical, topLeft, topRight, bottomLeft, bottomRight, topJoin, bottomJoin, leftJoin, rightJoin, center } = this.borderChars; const { borderColor } = this.options; const borderGradient = this.options.gradient.border; if (borderGradient && borderGradient.length === 2) { const chars = [topLeft, topRight, bottomLeft, bottomRight, horizontal, vertical, topJoin, bottomJoin, leftJoin, rightJoin, center]; const coloredChars = {}; chars.forEach((char, index) => { coloredChars[char] = this.generateGradientText(char, borderGradient[0], borderGradient[1]); }); bottomRight = coloredChars[bottomRight]; bottomLeft = coloredChars[bottomLeft]; topRight = coloredChars[topRight]; topLeft = coloredChars[topLeft]; horizontal = coloredChars[horizontal]; vertical = coloredChars[vertical]; bottomJoin = coloredChars[bottomJoin]; rightJoin = coloredChars[rightJoin]; leftJoin = coloredChars[leftJoin]; topJoin = coloredChars[topJoin]; center = coloredChars[center]; } else if (borderColor) { bottomRight = borderColor(bottomRight); bottomLeft = borderColor(bottomLeft); topRight = borderColor(topRight); topLeft = borderColor(topLeft); horizontal = borderColor(horizontal); vertical = borderColor(vertical); bottomJoin = borderColor(bottomJoin); rightJoin = borderColor(rightJoin); leftJoin = borderColor(leftJoin); topJoin = borderColor(topJoin); center = borderColor(center); } let border = ""; columns.forEach((column, index) => { const first = index === 0; const last = index === columns.length - 1; const width = columnWidths[column]; const line = horizontal.repeat(width); if (type === "top") { border += first ? topLeft : topJoin; } else if (type === "bottom") { border += first ? bottomLeft : bottomJoin; } else { border += first ? leftJoin : center; } border += line; if (last) { if (type === "top") { border += topRight; } else if (type === "bottom") { border += bottomRight; } else { border += rightJoin; } } }); return border; } generateRow(rowData, headerRow = false) { const { columns, columnWidths } = this; let { vertical } = this.borderChars; const { headerAlign, cellAlign, headerColor, cellColor } = this.options; const align = headerRow ? headerAlign : cellAlign; const headerGradient = this.options.gradient.header; const cellGradient = this.options.gradient.cell; const borderGradient = this.options.gradient.border; if (borderGradient && borderGradient.length === 2) { vertical = this.generateGradientText(vertical, borderGradient[0], borderGradient[1]); } else if (this.options.borderColor) { vertical = this.options.borderColor(vertical); } let row = ""; columns.forEach((column, index) => { const content = rowData[column] !== undefined ? String(rowData[column]) : ""; const width = columnWidths[column]; const alignedText = this.alignText(content, width, align); let cellContent = alignedText; const first = index === 0; if (headerRow) { if (headerGradient && headerGradient.length === 2) { cellContent = this.generateGradientText(cellContent, headerGradient[0], headerGradient[1]); } else if (headerColor) { cellContent = headerColor(cellContent); } } else { if (cellGradient && cellGradient.length === 2) { cellContent = this.generateGradientText(cellContent, cellGradient[0], cellGradient[1]); } else if (cellColor) { cellContent = cellColor(cellContent, column, rowData); } } if (first) { row += vertical; } row += cellContent + vertical; }); return row; } setTitle(title, tableNumber = null) { this.options.title = title; if (tableNumber !== null) { this.options.tableNumber = tableNumber; } } renderTitle() { let titleText = this.options.title; if (this.options.tableNumber !== null) { titleText = titleText; } const totalWidth = this.totalWidth - 2; const titleLength = titleText.length; let leftPadding = Math.floor((totalWidth - titleLength) / 2); if (leftPadding < 0) leftPadding = 0; let titleLine = " ".repeat(leftPadding) + titleText; const titleGradient = this.options.gradient.title; if (titleGradient && titleGradient.length === 2) { titleLine = this.generateGradientText(titleLine.trim(), titleGradient[0], titleGradient[1]); } return titleLine; } render() { const { data } = this; if (!data || data.length === 0) return ""; const lines = []; if (this.options.title) { const title = this.renderTitle(); lines.push(title); } lines.push(this.generateBorder("top")); const headerData = {}; this.columns.forEach(column => { headerData[column] = this.options.columnNames[column] || column; }); lines.push(this.generateRow(headerData, true)); lines.push(this.generateBorder("middle")); data.forEach(rowData => { lines.push(this.generateRow(rowData)); }); lines.push(this.generateBorder("bottom")); return lines.join("\n"); } } module.exports = ConsoleTable;