tablegger
Version:
Table logger
227 lines (221 loc) • 6.07 kB
JavaScript
'use strict';
const defu = require('defu');
const consola = require('consola');
const stringWidth = require('string-width');
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
const stringWidth__default = /*#__PURE__*/_interopDefaultCompat(stringWidth);
const defaultOption = {
table: {
border: false
},
cell: {
paddingX: 0,
paddingY: 0,
align: "left",
gapX: 0
}
};
class Tablegger {
constructor(option) {
/**
* User's data source
*/
this.data = [[]];
/**
* Current row index
*/
this.i = 0;
/**
* Current column index
*/
this.j = 0;
/**
* Maximum valid character width for each column
*/
this.columnsWidth = [];
/**
* Output result
*/
this.result = "";
/**
* Columns for table
* Must be set by `SetColumn` or `SetHeader`
* @default 3
*/
this.column = 3;
this.option = defu.defu(option, defaultOption);
}
push(word) {
if (this.j >= this.column) {
this.i++;
this.j = 0;
this.data.push(new Array(this.column).fill(""));
}
this.data[this.i][this.j] = word;
this.j++;
}
calcColumnsWidth() {
for (let j = 0; j < this.column; j++) {
const columWords = [];
for (let i = 0; i < this.data.length; i++)
columWords.push(this.data[i][j]);
this.columnsWidth[j] = calcMaxEffectWordLength(columWords);
}
}
addBorderHeader() {
const { cell: { paddingX } } = this.option;
this.result += "\u250C";
this.columnsWidth.map((column) => column + paddingX * 2).forEach((column, index) => {
this.result += "\u2500".repeat(column);
if (index < this.columnsWidth.length - 1)
this.result += "\u252C";
});
this.result += "\u2510\n";
}
addBorderRow() {
const { cell: { paddingX } } = this.option;
this.result += "\u251C";
this.columnsWidth.map((column) => column + paddingX * 2).forEach((column, index) => {
this.result += "\u2500".repeat(column);
if (index < this.columnsWidth.length - 1)
this.result += "\u253C";
});
this.result += "\u2524\n";
}
addPaddingYRow() {
const { table: { border }, cell: { paddingX } } = this.option;
if (border) {
this.result += "\u2502";
this.columnsWidth.map((column) => column + paddingX * 2).forEach((column, index) => {
this.result += " ".repeat(column);
if (index < this.columnsWidth.length - 1)
this.result += "\u2502";
});
this.result += "\u2502\n";
} else {
this.result += "\n".repeat(this.option.cell.paddingY);
}
}
addBorderFooter() {
const { cell: { paddingX } } = this.option;
this.result += "\u2514";
this.columnsWidth.map((column) => column + paddingX * 2).forEach((column, index) => {
this.result += "\u2500".repeat(column);
if (index < this.columnsWidth.length - 1)
this.result += "\u2534";
});
this.result += "\u2518\n";
}
/**
* Add table elements
* @param words
*/
add(words = "") {
if (!Array.isArray(words))
this.push(words.toString());
else
words.forEach((word) => this.push(word.toString()));
return this;
}
/**
* Set table header
* @param words
*/
setHeader(words) {
this.column = words.length;
this.add(words);
return this;
}
/**
* Set the number of table columns
* @param column
*/
setColumn(column) {
this.data = new Array(
new Array(column).fill("")
);
this.columnsWidth = new Array(column);
return this;
}
/**
* Modify data at a location
* @param i Abscissa
* @param j Ordinate
* @param word your data
*/
set(i, j, word) {
if (i > this.i || j > this.j)
consola.consola.error(`Invalid parameters, i must be less than or equal to ${this.i}, and j must be greater than or equal to ${this.j}`);
this.data[i][j] = word;
return this;
}
/**
* Override config
* @param option
*/
setConfig(option) {
this.option = defu.defu(option, this.option);
return this;
}
/**
* Get raw data
*/
get rawData() {
return this.data;
}
/**
* Generate result
*/
toString() {
const { table: { border }, cell: { paddingY } } = this.option;
this.result = "";
this.calcColumnsWidth();
if (border)
this.addBorderHeader();
for (let i = 0; i < this.data.length; i++) {
let t = 0;
while (t++ < paddingY)
this.addPaddingYRow();
if (border)
this.result += "\u2502";
for (let j = 0; j < this.data[i].length; j++) {
this.result += " ".repeat(this.option.cell.paddingX);
const rawWord = this.data[i][j];
const pureWordLen = stringWidth__default(rawWord);
const gapLen = this.columnsWidth[j] - pureWordLen;
if (this.option.cell.align === "right") {
this.result = this.result + " ".repeat(gapLen) + rawWord;
} else if (this.option.cell.align === "left") {
this.result = this.result + rawWord + " ".repeat(gapLen);
} else {
const startLen = Math.floor(gapLen / 2);
const endLen = gapLen - startLen;
this.result = this.result + " ".repeat(startLen) + rawWord + " ".repeat(endLen);
}
this.result += " ".repeat(this.option.cell.paddingX);
if (border)
this.result += "\u2502";
if (j < this.data[i].length - 1)
this.result += " ".repeat(this.option.cell.gapX);
}
this.result += "\n";
t = 0;
while (t++ < paddingY)
this.addPaddingYRow();
if (border && i < this.data.length - 1)
this.addBorderRow();
}
if (border)
this.addBorderFooter();
return this.result;
}
}
function calcMaxEffectWordLength(rawWords) {
let len = 0;
for (const word of rawWords) {
const effectWordLength = stringWidth__default(word);
len = Math.max(len, effectWordLength);
}
return len;
}
exports.Tablegger = Tablegger;