Table
Produces a string that represents array data in a text table.
Features
Works with strings containing fullwidth characters.
Configurable border characters.
Configurable content alignment per column.
Configurable content padding per column.
Configurable column width.
Install
Usage
Table data is described using an array (rows) of array (cells).
Copy import {
table
} from 'table' ;
// Using commonjs?
// const {table} = require('table');
let data ,
output;
data = [
[ '0A' , '0B' , '0C' ] ,
[ '1A' , '1B' , '1C' ] ,
[ '2A' , '2B' , '2C' ]
];
/**
* @typedef {string} table~cell
*/
/**
* @typedef {table~cell[]} table~row
*/
/**
* @typedef {Object} table~columns
* @property {string} alignment Cell content alignment (enum: left, center, right) (default: left).
* @property {number} width Column width (default: auto).
* @property {number} truncate Number of characters are which the content will be truncated (default: Infinity).
* @property {number} paddingLeft Cell content padding width left (default: 1).
* @property {number} paddingRight Cell content padding width right (default: 1).
*/
/**
* @typedef {Object} table~border
* @property {string} topBody
* @property {string} topJoin
* @property {string} topLeft
* @property {string} topRight
* @property {string} bottomBody
* @property {string} bottomJoin
* @property {string} bottomLeft
* @property {string} bottomRight
* @property {string} bodyLeft
* @property {string} bodyRight
* @property {string} bodyJoin
* @property {string} joinBody
* @property {string} joinLeft
* @property {string} joinRight
* @property {string} joinJoin
*/
/**
* Used to dynamically tell table whether to draw a line separating rows or not.
* The default behavior is to always return true.
*
* @typedef {function} drawHorizontalLine
* @param {number} index
* @param {number} size
* @return {boolean}
*/
/**
* @typedef {Object} table~config
* @property {table~border} border
* @property {table~columns[]} columns Column specific configuration.
* @property {table~columns} columnDefault Default values for all columns. Column specific settings overwrite the default values.
* @property {table~drawHorizontalLine} drawHorizontalLine
*/
/**
* Generates a text table.
*
* @param {table~row[]} rows
* @param {table~config} config
* @return {String}
*/
output = table (data);
console .log (output);
Copy ╔════╤════╤════╗
║ 0A │ 0B │ 0C ║
╟────┼────┼────╢
║ 1A │ 1B │ 1C ║
╟────┼────┼────╢
║ 2A │ 2B │ 2C ║
╚════╧════╧════╝
Cell Content Alignment
{string} config.columns[{number}].alignment
property controls content horizontal alignment within a cell.
Valid values are: "left", "right" and "center".
Copy let config ,
data ,
output;
data = [
[ '0A' , '0B' , '0C' ] ,
[ '1A' , '1B' , '1C' ] ,
[ '2A' , '2B' , '2C' ]
];
config = {
columns : {
0 : {
alignment : 'left' ,
width : 10
} ,
1 : {
alignment : 'center' ,
width : 10
} ,
2 : {
alignment : 'right' ,
width : 10
}
}
};
output = table (data , config);
console .log (output);
Copy ╔════════════╤════════════╤════════════╗
║ 0A │ 0B │ 0C ║
╟────────────┼────────────┼────────────╢
║ 1A │ 1B │ 1C ║
╟────────────┼────────────┼────────────╢
║ 2A │ 2B │ 2C ║
╚════════════╧════════════╧════════════╝
Column Width
{number} config.columns[{number}].width
property restricts column width to a fixed width.
Copy let data ,
output ,
options;
data = [
[ '0A' , '0B' , '0C' ] ,
[ '1A' , '1B' , '1C' ] ,
[ '2A' , '2B' , '2C' ]
];
options = {
columns : {
1 : {
width : 10
}
}
};
output = table (data , options);
console .log (output);
Copy ╔════╤════════════╤════╗
║ 0A │ 0B │ 0C ║
╟────┼────────────┼────╢
║ 1A │ 1B │ 1C ║
╟────┼────────────┼────╢
║ 2A │ 2B │ 2C ║
╚════╧════════════╧════╝
Custom Border
{object} config.border
property describes characters used to draw the table border.
Copy let config ,
data ,
output;
data = [
[ '0A' , '0B' , '0C' ] ,
[ '1A' , '1B' , '1C' ] ,
[ '2A' , '2B' , '2C' ]
];
config = {
border : {
topBody : `─` ,
topJoin : `┬` ,
topLeft : `┌` ,
topRight : `┐` ,
bottomBody : `─` ,
bottomJoin : `┴` ,
bottomLeft : `└` ,
bottomRight : `┘` ,
bodyLeft : `│` ,
bodyRight : `│` ,
bodyJoin : `│` ,
joinBody : `─` ,
joinLeft : `├` ,
joinRight : `┤` ,
joinJoin : `┼`
}
};
output = table (data , config);
console .log (output);
Copy ┌────┬────┬────┐
│ 0A │ 0B │ 0C │
├────┼────┼────┤
│ 1A │ 1B │ 1C │
├────┼────┼────┤
│ 2A │ 2B │ 2C │
└────┴────┴────┘
Draw Horizontal Line
{function} config.drawHorizontalLine
property is a function that is called for every non-content row in the table. The result of the function {boolean}
determines whether a row is drawn.
Copy let data ,
output ,
options;
data = [
[ '0A' , '0B' , '0C' ] ,
[ '1A' , '1B' , '1C' ] ,
[ '2A' , '2B' , '2C' ] ,
[ '3A' , '3B' , '3C' ] ,
[ '4A' , '4B' , '4C' ]
];
options = {
/**
* @typedef {function} drawHorizontalLine
* @param {number} index
* @param {number} size
* @return {boolean}
*/
drawHorizontalLine : (index , size) => {
return index === 0 || index === 1 || index === size - 1 || index === size;
}
};
output = table (data , options);
console .log (output);
Copy ╔════╤════╤════╗
║ 0A │ 0B │ 0C ║
╟────┼────┼────╢
║ 1A │ 1B │ 1C ║
║ 2A │ 2B │ 2C ║
║ 3A │ 3B │ 3C ║
╟────┼────┼────╢
║ 4A │ 4B │ 4C ║
╚════╧════╧════╝
Single Line Mode
Horizontal lines inside the table are not drawn.
Copy import {
table ,
getBorderCharacters
} from 'table' ;
const data = [
[ '-rw-r--r--' , '1' , 'pandorym' , 'staff' , '1529' , 'May 23 11:25' , 'LICENSE' ] ,
[ '-rw-r--r--' , '1' , 'pandorym' , 'staff' , '16327' , 'May 23 11:58' , 'README.md' ] ,
[ 'drwxr-xr-x' , '76' , 'pandorym' , 'staff' , '2432' , 'May 23 12:02' , 'dist' ] ,
[ 'drwxr-xr-x' , '634' , 'pandorym' , 'staff' , '20288' , 'May 23 11:54' , 'node_modules' ] ,
[ '-rw-r--r--' , '1,' , 'pandorym' , 'staff' , '525688' , 'May 23 11:52' , 'package-lock.json' ] ,
[ '-rw-r--r--@' , '1' , 'pandorym' , 'staff' , '2440' , 'May 23 11:25' , 'package.json' ] ,
[ 'drwxr-xr-x' , '27' , 'pandorym' , 'staff' , '864' , 'May 23 11:25' , 'src' ] ,
[ 'drwxr-xr-x' , '20' , 'pandorym' , 'staff' , '640' , 'May 23 11:25' , 'test' ] ,
];
const config = {
singleLine : true
};
const output = table (data , config);
console .log (output);
Copy ╔═════════════╤═════╤══════════╤═══════╤════════╤══════════════╤═══════════════════╗
║ -rw-r--r-- │ 1 │ pandorym │ staff │ 1529 │ May 23 11:25 │ LICENSE ║
║ -rw-r--r-- │ 1 │ pandorym │ staff │ 16327 │ May 23 11:58 │ README.md ║
║ drwxr-xr-x │ 76 │ pandorym │ staff │ 2432 │ May 23 12:02 │ dist ║
║ drwxr-xr-x │ 634 │ pandorym │ staff │ 20288 │ May 23 11:54 │ node_modules ║
║ -rw-r--r-- │ 1, │ pandorym │ staff │ 525688 │ May 23 11:52 │ package-lock.json ║
║ -rw-r--r--@ │ 1 │ pandorym │ staff │ 2440 │ May 23 11:25 │ package.json ║
║ drwxr-xr-x │ 27 │ pandorym │ staff │ 864 │ May 23 11:25 │ src ║
║ drwxr-xr-x │ 20 │ pandorym │ staff │ 640 │ May 23 11:25 │ test ║
╚═════════════╧═════╧══════════╧═══════╧════════╧══════════════╧═══════════════════╝
Padding Cell Content
{number} config.columns[{number}].paddingLeft
and {number} config.columns[{number}].paddingRight
properties control content padding within a cell. Property value represents a number of whitespaces used to pad the content.
Copy let config ,
data ,
output;
data = [
[ '0A' , 'AABBCC' , '0C' ] ,
[ '1A' , '1B' , '1C' ] ,
[ '2A' , '2B' , '2C' ]
];
config = {
columns : {
0 : {
paddingLeft : 3
} ,
1 : {
width : 2 ,
paddingRight : 3
}
}
};
output = table (data , config);
console .log (output);
Copy ╔══════╤══════╤════╗
║ 0A │ AA │ 0C ║
║ │ BB │ ║
║ │ CC │ ║
╟──────┼──────┼────╢
║ 1A │ 1B │ 1C ║
╟──────┼──────┼────╢
║ 2A │ 2B │ 2C ║
╚══════╧══════╧════╝
Predefined Border Templates
You can load one of the predefined border templates using getBorderCharacters
function.
Copy import {
table ,
getBorderCharacters
} from 'table' ;
let config ,
data;
data = [
[ '0A' , '0B' , '0C' ] ,
[ '1A' , '1B' , '1C' ] ,
[ '2A' , '2B' , '2C' ]
];
config = {
border : getBorderCharacters ( `name of the template` )
};
table (data , config);
Copy # honeywell
╔════╤════╤════╗
║ 0A │ 0B │ 0C ║
╟────┼────┼────╢
║ 1A │ 1B │ 1C ║
╟────┼────┼────╢
║ 2A │ 2B │ 2C ║
╚════╧════╧════╝
# norc
┌────┬────┬────┐
│ 0A │ 0B │ 0C │
├────┼────┼────┤
│ 1A │ 1B │ 1C │
├────┼────┼────┤
│ 2A │ 2B │ 2C │
└────┴────┴────┘
# ramac (ASCII; for use in terminals that do not support Unicode characters)
+----+----+----+
| 0A | 0B | 0C |
|----|----|----|
| 1A | 1B | 1C |
|----|----|----|
| 2A | 2B | 2C |
+----+----+----+
# void (no borders; see "bordless table" section of the documentation)
0A 0B 0C
1A 1B 1C
2A 2B 2C
Raise an issue if you'd like to contribute a new border template.
Borderless Table
Simply using "void" border character template creates a table with a lot of unnecessary spacing.
To create a more plesant to the eye table, reset the padding and remove the joining rows, e.g.
Copy let output;
output = table (data , {
border : getBorderCharacters ( `void` ) ,
columnDefault : {
paddingLeft : 0 ,
paddingRight : 1
} ,
drawHorizontalLine : () => {
return false
}
});
console .log (output);
Copy 0A 0B 0C
1A 1B 1C
2A 2B 2C
Streaming
table
package exports createStream
function used to draw a table and append rows.
createStream
requires {number} columnDefault.width
and {number} columnCount
configuration properties.
Copy import {
createStream
} from 'table' ;
let config ,
stream;
config = {
columnDefault : {
width : 50
} ,
columnCount : 1
};
stream = createStream (config);
setInterval (() => {
stream .write ([ new Date ()]);
} , 500 );
table
package uses ANSI escape codes to overwrite the output of the last line when a new row is printed.
The underlying implementation is explained in this Stack Overflow answer .
Streaming supports all of the configuration properties and functionality of a static table (such as auto text wrapping, alignment and padding), e.g.
Copy import {
createStream
} from 'table' ;
import _ from 'lodash' ;
let config ,
stream ,
i;
config = {
columnDefault : {
width : 50
} ,
columnCount : 3 ,
columns : {
0 : {
width : 10 ,
alignment : 'right'
} ,
1 : {
alignment : 'center' ,
} ,
2 : {
width : 10
}
}
};
stream = createStream (config);
i = 0 ;
setInterval (() => {
let random;
random = _ .sample ( 'abcdefghijklmnopqrstuvwxyz' , _ .random ( 1 , 30 )) .join ( '' );
stream .write ([i ++ , new Date () , random]);
} , 500 );
Text Truncation
To handle a content that overflows the container width, table
package implements text wrapping . However, sometimes you may want to truncate content that is too long to be displayed in the table.
{number} config.columns[{number}].truncate
property (default: Infinity
) truncates the text at the specified length.
Copy let config ,
data ,
output;
data = [
['Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus pulvinar nibh sed mauris convallis dapibus. Nunc venenatis tempus nulla sit amet viverra.']
];
config = {
columns : {
0 : {
width : 20 ,
truncate : 100
}
}
};
output = table (data , config);
console .log (output);
Copy ╔══════════════════════╗
║ Lorem ipsum dolor si ║
║ t amet, consectetur ║
║ adipiscing elit. Pha ║
║ sellus pulvinar nibh ║
║ sed mauris conva... ║
╚══════════════════════╝
Text Wrapping
table
package implements auto text wrapping, i.e. text that has width greater than the container width will be separated into multiple lines, e.g.
Copy let config ,
data ,
output;
data = [
['Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus pulvinar nibh sed mauris convallis dapibus. Nunc venenatis tempus nulla sit amet viverra.']
];
config = {
columns : {
0 : {
width : 20
}
}
};
output = table (data , config);
console .log (output);
Copy ╔══════════════════════╗
║ Lorem ipsum dolor si ║
║ t amet, consectetur ║
║ adipiscing elit. Pha ║
║ sellus pulvinar nibh ║
║ sed mauris convallis ║
║ dapibus. Nunc venena ║
║ tis tempus nulla sit ║
║ amet viverra. ║
╚══════════════════════╝
When wrapWord
is true
the text is broken at the nearest space or one of the special characters ("-", "_", "", "/", ".", ",", ";"), e.g.
Copy let config ,
data ,
output;
data = [
['Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus pulvinar nibh sed mauris convallis dapibus. Nunc venenatis tempus nulla sit amet viverra.']
];
config = {
columns : {
0 : {
width : 20 ,
wrapWord : true
}
}
};
output = table (data , config);
console .log (output);
Copy ╔══════════════════════╗
║ Lorem ipsum dolor ║
║ sit amet, ║
║ consectetur ║
║ adipiscing elit. ║
║ Phasellus pulvinar ║
║ nibh sed mauris ║
║ convallis dapibus. ║
║ Nunc venenatis ║
║ tempus nulla sit ║
║ amet viverra. ║
╚══════════════════════╝