table

by gajus

gajus / table

Formats data into a string table.

459 Stars 57 Forks Last release: about 2 months ago (v6.0.3) Other 204 Commits 50 Releases

Available items

No Items, yet!

The developer of this repository has not created any items for sale yet. Need a bug fixed? Help with integration? A different license? Create a request here:

Table

GitSpo Mentions Travis build status Coveralls NPM version Canonical Code Style Twitter Follow

Produces a string that represents array data in a text table.

Demo of table displaying a list of missions to the Moon.

Features

  • 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.

Install

npm install table

Buy Me A Coffee Become a Patron

Usage

Table data is described using an array (rows) of array (cells).

import tableImport from 'table';
const { table } = tableImport;

// Using commonjs? // const {table} = require('table');

let data, output;

data = [ ['0A', '0B', '0C'], ['1A', '1B', '1C'], ['2A', '2B', '2C'] ];

/**

  • @typedef {string} table~cell
  • /

/**

  • @typedef {tablecell[]} tablerow
  • /

/**

  • @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 ║
╚════╧════╧════╝

Cell Content Alignment

{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', width: 10 }, 1: { alignment: 'center', width: 10 }, 2: { alignment: 'right', width: 10 } } };

output = table(data, config);

console.log(output);

╔════════════╤════════════╤════════════╗
║ 0A         │     0B     │         0C ║
╟────────────┼────────────┼────────────╢
║ 1A         │     1B     │         1C ║
╟────────────┼────────────┼────────────╢
║ 2A         │     2B     │         2C ║
╚════════════╧════════════╧════════════╝

Column Width

{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 ║
╚════╧════════════╧════╝

Custom Border

{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 │
└────┴────┴────┘

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.
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 ║
╚════╧════╧════╝

Single Line Mode

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'], ['[email protected]', '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 ║
║ [email protected] │ 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.
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 ║
╚══════╧══════╧════╝

Predefined Border Templates

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.

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.

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

Streaming

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);

Streaming current date.

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);

Streaming random data.

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.
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...  ║
╚══════════════════════╝

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.
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.        ║
╚══════════════════════╝

We use cookies. If you continue to browse the site, you agree to the use of cookies. For more information on our use of cookies please see our Privacy Policy.