wishthis/node_modules/cli-table/lib/index.js
2022-01-21 09:28:41 +01:00

304 lines
7.7 KiB
JavaScript

/**
* Module dependencies.
*/
var colors = require('colors/safe')
, utils = require('./utils')
, repeat = utils.repeat
, truncate = utils.truncate
, pad = utils.pad;
/**
* Table constructor
*
* @param {Object} options
* @api public
*/
function Table (options){
this.options = utils.options({
chars: {
'top': '─'
, 'top-mid': '┬'
, 'top-left': '┌'
, 'top-right': '┐'
, 'bottom': '─'
, 'bottom-mid': '┴'
, 'bottom-left': '└'
, 'bottom-right': '┘'
, 'left': '│'
, 'left-mid': '├'
, 'mid': '─'
, 'mid-mid': '┼'
, 'right': '│'
, 'right-mid': '┤'
, 'middle': '│'
}
, truncate: '…'
, colWidths: []
, colAligns: []
, style: {
'padding-left': 1
, 'padding-right': 1
, head: ['red']
, border: ['grey']
, compact : false
}
, head: []
}, options);
if (options && options.rows) {
for (var i = 0; i < options.rows.length; i++) {
this.push(options.rows[i]);
}
}
}
/**
* Inherit from Array.
*/
Table.prototype.__proto__ = Array.prototype;
/**
* Width getter
*
* @return {Number} width
* @api public
*/
Table.prototype.__defineGetter__('width', function (){
var str = this.toString().split("\n");
if (str.length) return str[0].length;
return 0;
});
/**
* Render to a string.
*
* @return {String} table representation
* @api public
*/
Table.prototype.render
Table.prototype.toString = function (){
var ret = ''
, options = this.options
, style = options.style
, head = options.head
, chars = options.chars
, truncater = options.truncate
, colWidths = options.colWidths || new Array(this.head.length)
, totalWidth = 0;
if (!head.length && !this.length) return '';
if (!colWidths.length){
var all_rows = this.slice(0);
if (head.length) { all_rows = all_rows.concat([head]) };
all_rows.forEach(function(cells){
// horizontal (arrays)
if (typeof cells === 'object' && cells.length) {
extractColumnWidths(cells);
// vertical (objects)
} else {
var header_cell = Object.keys(cells)[0]
, value_cell = cells[header_cell];
colWidths[0] = Math.max(colWidths[0] || 0, get_width(header_cell) || 0);
// cross (objects w/ array values)
if (typeof value_cell === 'object' && value_cell.length) {
extractColumnWidths(value_cell, 1);
} else {
colWidths[1] = Math.max(colWidths[1] || 0, get_width(value_cell) || 0);
}
}
});
};
totalWidth = (colWidths.length == 1 ? colWidths[0] : colWidths.reduce(
function (a, b){
return a + b
})) + colWidths.length + 1;
function extractColumnWidths(arr, offset) {
var offset = offset || 0;
arr.forEach(function(cell, i){
colWidths[i + offset] = Math.max(colWidths[i + offset] || 0, get_width(cell) || 0);
});
};
function get_width(obj) {
return typeof obj == 'object' && obj.width != undefined
? obj.width
: ((typeof obj == 'object' ? utils.strlen(obj.text) : utils.strlen(obj)) + (style['padding-left'] || 0) + (style['padding-right'] || 0))
}
// draws a line
function line (line, left, right, intersection){
var width = 0
, line =
left
+ repeat(line, totalWidth - 2)
+ right;
colWidths.forEach(function (w, i){
if (i == colWidths.length - 1) return;
width += w + 1;
line = line.substr(0, width) + intersection + line.substr(width + 1);
});
return applyStyles(options.style.border, line);
};
// draws the top line
function lineTop (){
var l = line(chars.top
, chars['top-left'] || chars.top
, chars['top-right'] || chars.top
, chars['top-mid']);
if (l)
ret += l + "\n";
};
function generateRow (items, style) {
var cells = []
, max_height = 0;
// prepare vertical and cross table data
if (!Array.isArray(items) && typeof items === "object") {
var key = Object.keys(items)[0]
, value = items[key]
, first_cell_head = true;
if (Array.isArray(value)) {
items = value;
items.unshift(key);
} else {
items = [key, value];
}
}
// transform array of item strings into structure of cells
items.forEach(function (item, i) {
var contents = item.toString().split("\n").reduce(function (memo, l) {
memo.push(string(l, i));
return memo;
}, [])
var height = contents.length;
if (height > max_height) { max_height = height };
cells.push({ contents: contents , height: height });
});
// transform vertical cells into horizontal lines
var lines = new Array(max_height);
cells.forEach(function (cell, i) {
cell.contents.forEach(function (line, j) {
if (!lines[j]) { lines[j] = [] };
if (style || (first_cell_head && i === 0 && options.style.head)) {
line = applyStyles(options.style.head, line)
}
lines[j].push(line);
});
// populate empty lines in cell
for (var j = cell.height, l = max_height; j < l; j++) {
if (!lines[j]) { lines[j] = [] };
lines[j].push(string('', i));
}
});
var ret = "";
lines.forEach(function (line, index) {
if (ret.length > 0) {
ret += "\n" + applyStyles(options.style.border, chars.left);
}
ret += line.join(applyStyles(options.style.border, chars.middle)) + applyStyles(options.style.border, chars.right);
});
return applyStyles(options.style.border, chars.left) + ret;
};
function applyStyles(styles, subject) {
if (!subject)
return '';
styles.forEach(function(style) {
subject = colors[style](subject);
});
return subject;
};
// renders a string, by padding it or truncating it
function string (str, index){
var str = String(typeof str == 'object' && str.text ? str.text : str)
, length = utils.strlen(str)
, width = colWidths[index]
- (style['padding-left'] || 0)
- (style['padding-right'] || 0)
, align = options.colAligns[index] || 'left';
return repeat(' ', style['padding-left'] || 0)
+ (length == width ? str :
(length < width
? pad(str, ( width + (str.length - length) ), ' ', align == 'left' ? 'right' :
(align == 'middle' ? 'both' : 'left'))
: (truncater ? truncate(str, width, truncater) : str))
)
+ repeat(' ', style['padding-right'] || 0);
};
if (head.length){
lineTop();
ret += generateRow(head, style.head) + "\n"
}
if (this.length)
this.forEach(function (cells, i){
if (!head.length && i == 0)
lineTop();
else {
if (!style.compact || i<(!!head.length) ?1:0 || cells.length == 0){
var l = line(chars.mid
, chars['left-mid']
, chars['right-mid']
, chars['mid-mid']);
if (l)
ret += l + "\n"
}
}
if (cells.hasOwnProperty("length") && !cells.length) {
return
} else {
ret += generateRow(cells) + "\n";
};
});
var l = line(chars.bottom
, chars['bottom-left'] || chars.bottom
, chars['bottom-right'] || chars.bottom
, chars['bottom-mid']);
if (l)
ret += l;
else
// trim the last '\n' if we didn't add the bottom decoration
ret = ret.slice(0, -1);
return ret;
};
/**
* Module exports.
*/
module.exports = Table;
module.exports.version = '0.0.1';