Produces a string that represents array data in a text table.
- Works with strings containing fullwidth characters.
- Works with strings containing ANSI escape codes.
- Configurable border characters.
- Configurable content alignment per column.
- Configurable content padding per column.
- Configurable column width.
- Text wrapping.
npm install table
Table data is described using an array (rows) of array (cells).
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);
ββββββ€βββββ€βββββ
β 0A β 0B β 0C β
ββββββΌβββββΌβββββ’
β 1A β 1B β 1C β
ββββββΌβββββΌβββββ’
β 2A β 2B β 2C β
ββββββ§βββββ§βββββ
{string} config.columns[{number}].alignment
property controls content horizontal alignment within a cell.
Valid values are: "left", "right" and "center".
let config,
data,
output;
data = [
['0A', '0B', '0C'],
['1A', '1B', '1C'],
['2A', '2B', '2C']
];
config = {
columns: {
0: {
alignment: 'left',
minWidth: 10
},
1: {
alignment: 'center',
minWidth: 10
},
2: {
alignment: 'right',
minWidth: 10
}
}
};
output = table(data, config);
console.log(output);
ββββββββββββββ€βββββββββββββ€βββββββββββββ
β 0A β 0B β 0C β
ββββββββββββββΌβββββββββββββΌβββββββββββββ’
β 1A β 1B β 1C β
ββββββββββββββΌβββββββββββββΌβββββββββββββ’
β 2A β 2B β 2C β
ββββββββββββββ§βββββββββββββ§βββββββββββββ
{number} config.columns[{number}].width
property restricts column width to a fixed width.
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);
ββββββ€βββββββββββββ€βββββ
β 0A β 0B β 0C β
ββββββΌβββββββββββββΌβββββ’
β 1A β 1B β 1C β
ββββββΌβββββββββββββΌβββββ’
β 2A β 2B β 2C β
ββββββ§βββββββββββββ§βββββ
{object} config.border
property describes characters used to draw the table border.
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);
ββββββ¬βββββ¬βββββ
β 0A β 0B β 0C β
ββββββΌβββββΌβββββ€
β 1A β 1B β 1C β
ββββββΌβββββΌβββββ€
β 2A β 2B β 2C β
ββββββ΄βββββ΄βββββ
{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.
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);
ββββββ€βββββ€βββββ
β 0A β 0B β 0C β
ββββββΌβββββΌβββββ’
β 1A β 1B β 1C β
β 2A β 2B β 2C β
β 3A β 3B β 3C β
ββββββΌβββββΌβββββ’
β 4A β 4B β 4C β
ββββββ§βββββ§βββββ
Horizontal lines inside the table are not drawn.
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);
βββββββββββββββ€ββββββ€βββββββββββ€ββββββββ€βββββββββ€βββββββββββββββ€ββββββββββββββββββββ
β -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 β
βββββββββββββββ§ββββββ§βββββββββββ§ββββββββ§βββββββββ§βββββββββββββββ§ββββββββββββββββββββ
{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.
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);
ββββββββ€βββββββ€βββββ
β 0A β AA β 0C β
β β BB β β
β β CC β β
ββββββββΌβββββββΌβββββ’
β 1A β 1B β 1C β
ββββββββΌβββββββΌβββββ’
β 2A β 2B β 2C β
ββββββββ§βββββββ§βββββ
You can load one of the predefined border templates using getBorderCharacters
function.
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);
# 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.
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.
let output;
output = table(data, {
border: getBorderCharacters(`void`),
columnDefault: {
paddingLeft: 0,
paddingRight: 1
},
drawHorizontalLine: () => {
return false
}
});
console.log(output);
0A 0B 0C
1A 1B 1C
2A 2B 2C
table
package exports createStream
function used to draw a table and append rows.
createStream
requires {number} columnDefault.width
and {number} columnCount
configuration properties.
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.
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);
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.
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);
ββββββββββββββββββββββββ
β Lorem ipsum dolor si β
β t amet, consectetur β
β adipiscing elit. Pha β
β sellus pulvinar nibh β
β sed mauris conva... β
ββββββββββββββββββββββββ
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.
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);
ββββββββββββββββββββββββ
β 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.
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);
ββββββββββββββββββββββββ
β Lorem ipsum dolor β
β sit amet, β
β consectetur β
β adipiscing elit. β
β Phasellus pulvinar β
β nibh sed mauris β
β convallis dapibus. β
β Nunc venenatis β
β tempus nulla sit β
β amet viverra. β
ββββββββββββββββββββββββ