arisu/node_modules/ascii-table/ascii-table.js
2025-04-27 15:36:04 +01:00

650 lines
14 KiB
JavaScript

/**
* (c) 2013 Beau Sorensen
* MIT Licensed
* For all details and documentation:
* https://github.com/sorensen/ascii-table
*/
;(function() {
'use strict';
/*!
* Module dependencies
*/
var slice = Array.prototype.slice
, toString = Object.prototype.toString
/**
* AsciiTable constructor
*
* @param {String|Object} title or JSON table
* @param {Object} table options
* - `prefix` - string prefix added to each line on render
* @constructor
* @api public
*/
function AsciiTable(name, options) {
this.options = options || {}
this.reset(name)
}
/*!
* Current library version, should match `package.json`
*/
AsciiTable.VERSION = '0.0.8'
/*!
* Alignment constants
*/
AsciiTable.LEFT = 0
AsciiTable.CENTER = 1
AsciiTable.RIGHT = 2
/*!
* Static methods
*/
/**
* Create a new table instance
*
* @param {String|Object} title or JSON table
* @param {Object} table options
* @api public
*/
AsciiTable.factory = function(name, options) {
return new AsciiTable(name, options)
}
/**
* Align the a string at the given length
*
* @param {Number} direction
* @param {String} string input
* @param {Number} string length
* @param {Number} padding character
* @api public
*/
AsciiTable.align = function(dir, str, len, pad) {
if (dir === AsciiTable.LEFT) return AsciiTable.alignLeft(str, len, pad)
if (dir === AsciiTable.RIGHT) return AsciiTable.alignRight(str, len, pad)
if (dir === AsciiTable.CENTER) return AsciiTable.alignCenter(str, len, pad)
return AsciiTable.alignAuto(str, len, pad)
}
/**
* Left align a string by padding it at a given length
*
* @param {String} str
* @param {Number} string length
* @param {String} padding character (optional, default '')
* @api public
*/
AsciiTable.alignLeft = function(str, len, pad) {
if (!len || len < 0) return ''
if (str === undefined || str === null) str = ''
if (typeof pad === 'undefined') pad = ' '
if (typeof str !== 'string') str = str.toString()
var alen = len + 1 - str.length
if (alen <= 0) return str
return str + Array(len + 1 - str.length).join(pad)
}
/**
* Center align a string by padding it at a given length
*
* @param {String} str
* @param {Number} string length
* @param {String} padding character (optional, default '')
* @api public
*/
AsciiTable.alignCenter = function(str, len, pad) {
if (!len || len < 0) return ''
if (str === undefined || str === null) str = ''
if (typeof pad === 'undefined') pad = ' '
if (typeof str !== 'string') str = str.toString()
var nLen = str.length
, half = Math.floor(len / 2 - nLen / 2)
, odds = Math.abs((nLen % 2) - (len % 2))
, len = str.length
return AsciiTable.alignRight('', half, pad)
+ str
+ AsciiTable.alignLeft('', half + odds, pad)
}
/**
* Right align a string by padding it at a given length
*
* @param {String} str
* @param {Number} string length
* @param {String} padding character (optional, default '')
* @api public
*/
AsciiTable.alignRight = function(str, len, pad) {
if (!len || len < 0) return ''
if (str === undefined || str === null) str = ''
if (typeof pad === 'undefined') pad = ' '
if (typeof str !== 'string') str = str.toString()
var alen = len + 1 - str.length
if (alen <= 0) return str
return Array(len + 1 - str.length).join(pad) + str
}
/**
* Auto align string value based on object type
*
* @param {Any} object to string
* @param {Number} string length
* @param {String} padding character (optional, default '')
* @api public
*/
AsciiTable.alignAuto = function(str, len, pad) {
if (str === undefined || str === null) str = ''
var type = toString.call(str)
pad || (pad = ' ')
len = +len
if (type !== '[object String]') {
str = str.toString()
}
if (str.length < len) {
switch(type) {
case '[object Number]': return AsciiTable.alignRight(str, len, pad)
default: return AsciiTable.alignLeft(str, len, pad)
}
}
return str
}
/**
* Fill an array at a given size with the given value
*
* @param {Number} array size
* @param {Any} fill value
* @return {Array} filled array
* @api public
*/
AsciiTable.arrayFill = function(len, fill) {
var arr = new Array(len)
for (var i = 0; i !== len; i++) {
arr[i] = fill;
}
return arr
}
/*!
* Instance methods
*/
/**
* Reset the table state back to defaults
*
* @param {String|Object} title or JSON table
* @api public
*/
AsciiTable.prototype.reset =
AsciiTable.prototype.clear = function(name) {
this.__name = ''
this.__nameAlign = AsciiTable.CENTER
this.__rows = []
this.__maxCells = 0
this.__aligns = []
this.__colMaxes = []
this.__spacing = 1
this.__heading = null
this.__headingAlign = AsciiTable.CENTER
this.setBorder()
if (toString.call(name) === '[object String]') {
this.__name = name
} else if (toString.call(name) === '[object Object]') {
this.fromJSON(name)
}
return this
}
/**
* Set the table border
*
* @param {String} horizontal edges (optional, default `|`)
* @param {String} vertical edges (optional, default `-`)
* @param {String} top corners (optional, default `.`)
* @param {String} bottom corners (optional, default `'`)
* @api public
*/
AsciiTable.prototype.setBorder = function(edge, fill, top, bottom) {
this.__border = true
if (arguments.length === 1) {
fill = top = bottom = edge
}
this.__edge = edge || '|'
this.__fill = fill || '-'
this.__top = top || '.'
this.__bottom = bottom || "'"
return this
}
/**
* Remove all table borders
*
* @api public
*/
AsciiTable.prototype.removeBorder = function() {
this.__border = false
this.__edge = ' '
this.__fill = ' '
return this
}
/**
* Set the column alignment at a given index
*
* @param {Number} column index
* @param {Number} alignment direction
* @api public
*/
AsciiTable.prototype.setAlign = function(idx, dir) {
this.__aligns[idx] = dir
return this
}
/**
* Set the title of the table
*
* @param {String} title
* @api public
*/
AsciiTable.prototype.setTitle = function(name) {
this.__name = name
return this
}
/**
* Get the title of the table
*
* @return {String} title
* @api public
*/
AsciiTable.prototype.getTitle = function() {
return this.__name
}
/**
* Set table title alignment
*
* @param {Number} direction
* @api public
*/
AsciiTable.prototype.setTitleAlign = function(dir) {
this.__nameAlign = dir
return this
}
/**
* AsciiTable sorting shortcut to sort rows
*
* @param {Function} sorting method
* @api public
*/
AsciiTable.prototype.sort = function(method) {
this.__rows.sort(method)
return this
}
/**
* Sort rows based on sort method for given column
*
* @param {Number} column index
* @param {Function} sorting method
* @api public
*/
AsciiTable.prototype.sortColumn = function(idx, method) {
this.__rows.sort(function(a, b) {
return method(a[idx], b[idx])
})
return this
}
/**
* Set table heading for columns
*
* @api public
*/
AsciiTable.prototype.setHeading = function(row) {
if (arguments.length > 1 || toString.call(row) !== '[object Array]') {
row = slice.call(arguments)
}
this.__heading = row
return this
}
/**
* Get table heading for columns
*
* @return {Array} copy of headings
* @api public
*/
AsciiTable.prototype.getHeading = function() {
return this.__heading.slice()
}
/**
* Set heading alignment
*
* @param {Number} direction
* @api public
*/
AsciiTable.prototype.setHeadingAlign = function(dir) {
this.__headingAlign = dir
return this
}
/**
* Add a row of information to the table
*
* @param {...|Array} argument values in order of columns
* @api public
*/
AsciiTable.prototype.addRow = function(row) {
if (arguments.length > 1 || toString.call(row) !== '[object Array]') {
row = slice.call(arguments)
}
this.__maxCells = Math.max(this.__maxCells, row.length)
this.__rows.push(row)
return this
}
/**
* Get a copy of all rows of the table
*
* @return {Array} copy of rows
* @api public
*/
AsciiTable.prototype.getRows = function() {
return this.__rows.slice().map(function(row) {
return row.slice()
})
}
/**
* Add rows in the format of a row matrix
*
* @param {Array} row matrix
* @api public
*/
AsciiTable.prototype.addRowMatrix = function(rows) {
for (var i = 0; i < rows.length; i++) {
this.addRow(rows[i])
}
return this
}
/**
* Add rows from the given data array, processed by the callback function rowCallback.
*
* @param {Array} data
* @param (Function) rowCallback
* @param (Boolean) asMatrix - controls if the row created by rowCallback should be assigned as row matrix
* @api public
*/
AsciiTable.prototype.addData = function(data, rowCallback, asMatrix) {
if (toString.call(data) !== '[object Array]') {
return this;
}
for (var index = 0, limit = data.length; index < limit; index++) {
var row = rowCallback(data[index]);
if(asMatrix) {
this.addRowMatrix(row);
} else {
this.addRow(row);
}
}
return this
}
/**
* Reset the current row state
*
* @api public
*/
AsciiTable.prototype.clearRows = function() {
this.__rows = []
this.__maxCells = 0
this.__colMaxes = []
return this
}
/**
* Apply an even spaced column justification
*
* @param {Boolean} on / off
* @api public
*/
AsciiTable.prototype.setJustify = function(val) {
arguments.length === 0 && (val = true)
this.__justify = !!val
return this
}
/**
* Convert the current instance to a JSON structure
*
* @return {Object} json representation
* @api public
*/
AsciiTable.prototype.toJSON = function() {
return {
title: this.getTitle()
, heading: this.getHeading()
, rows: this.getRows()
}
}
/**
* Populate the table from a JSON object
*
* @param {Object} json representation
* @api public
*/
AsciiTable.prototype.parse =
AsciiTable.prototype.fromJSON = function(obj) {
return this
.clear()
.setTitle(obj.title)
.setHeading(obj.heading)
.addRowMatrix(obj.rows)
}
/**
* Render the table with the current information
*
* @return {String} formatted table
* @api public
*/
AsciiTable.prototype.render =
AsciiTable.prototype.valueOf =
AsciiTable.prototype.toString = function() {
var self = this
, body = []
, mLen = this.__maxCells
, max = AsciiTable.arrayFill(mLen, 0)
, total = mLen * 3
, rows = this.__rows
, justify
, border = this.__border
, all = this.__heading
? [this.__heading].concat(rows)
: rows
// Calculate max table cell lengths across all rows
for (var i = 0; i < all.length; i++) {
var row = all[i]
for (var k = 0; k < mLen; k++) {
var cell = row[k]
max[k] = Math.max(max[k], cell ? cell.toString().length : 0)
}
}
this.__colMaxes = max
justify = this.__justify ? Math.max.apply(null, max) : 0
// Get
max.forEach(function(x) {
total += justify ? justify : x + self.__spacing
})
justify && (total += max.length)
total -= this.__spacing
// Heading
border && body.push(this._seperator(total - mLen + 1, this.__top))
if (this.__name) {
body.push(this._renderTitle(total - mLen + 1))
border && body.push(this._seperator(total - mLen + 1))
}
if (this.__heading) {
body.push(this._renderRow(this.__heading, ' ', this.__headingAlign))
body.push(this._rowSeperator(mLen, this.__fill))
}
for (var i = 0; i < this.__rows.length; i++) {
body.push(this._renderRow(this.__rows[i], ' '))
}
border && body.push(this._seperator(total - mLen + 1, this.__bottom))
var prefix = this.options.prefix || ''
return prefix + body.join('\n' + prefix)
}
/**
* Create a line seperator
*
* @param {Number} string size
* @param {String} side values (default '|')
* @api private
*/
AsciiTable.prototype._seperator = function(len, sep) {
sep || (sep = this.__edge)
return sep + AsciiTable.alignRight(sep, len, this.__fill)
}
/**
* Create a row seperator
*
* @return {String} seperator
* @api private
*/
AsciiTable.prototype._rowSeperator = function() {
var blanks = AsciiTable.arrayFill(this.__maxCells, this.__fill)
return this._renderRow(blanks, this.__fill)
}
/**
* Render the table title in a centered box
*
* @param {Number} string size
* @return {String} formatted title
* @api private
*/
AsciiTable.prototype._renderTitle = function(len) {
var name = ' ' + this.__name + ' '
, str = AsciiTable.align(this.__nameAlign, name, len - 1, ' ')
return this.__edge + str + this.__edge
}
/**
* Render an invdividual row
*
* @param {Array} row
* @param {String} column seperator
* @param {Number} total row alignment (optional, default `auto`)
* @return {String} formatted row
* @api private
*/
AsciiTable.prototype._renderRow = function(row, str, align) {
var tmp = ['']
, max = this.__colMaxes
for (var k = 0; k < this.__maxCells; k++) {
var cell = row[k]
, just = this.__justify ? Math.max.apply(null, max) : max[k]
// , pad = k === this.__maxCells - 1 ? just : just + this.__spacing
, pad = just
, cAlign = this.__aligns[k]
, use = align
, method = 'alignAuto'
if (typeof align === 'undefined') use = cAlign
if (use === AsciiTable.LEFT) method = 'alignLeft'
if (use === AsciiTable.CENTER) method = 'alignCenter'
if (use === AsciiTable.RIGHT) method = 'alignRight'
tmp.push(AsciiTable[method](cell, pad, str))
}
var front = tmp.join(str + this.__edge + str)
front = front.substr(1, front.length)
return front + str + this.__edge
}
/*!
* Aliases
*/
// Create method shortcuts to all alignment methods for each direction
;['Left', 'Right', 'Center'].forEach(function(dir) {
var constant = AsciiTable[dir.toUpperCase()]
;['setAlign', 'setTitleAlign', 'setHeadingAlign'].forEach(function(method) {
// Call the base method with the direction constant as the last argument
AsciiTable.prototype[method + dir] = function() {
var args = slice.call(arguments).concat(constant)
return this[method].apply(this, args)
}
})
})
/*!
* Module exports.
*/
if (typeof exports !== 'undefined') {
module.exports = AsciiTable
} else {
this.AsciiTable = AsciiTable
}
}).call(this);