Gathering detailed insights and metrics for table
Gathering detailed insights and metrics for table
Gathering detailed insights and metrics for table
Gathering detailed insights and metrics for table
npm install table
Module System
Min. Node Version
Typescript Support
Node Version
NPM Version
907 Stars
261 Commits
76 Forks
11 Watching
8 Branches
27 Contributors
Updated on 21 Nov 2024
TypeScript (99.43%)
JavaScript (0.57%)
Cumulative downloads
Total Downloads
Last day
-9%
3,147,015
Compared to previous day
Last week
0.6%
19,194,556
Compared to previous week
Last month
26.8%
74,250,366
Compared to previous month
Last year
-9.6%
740,025,290
Compared to previous year
5
Produces a string that represents array data in a text table.
1npm install table
1import { table } from 'table'; 2 3// Using commonjs? 4// const { table } = require('table'); 5 6const data = [ 7 ['0A', '0B', '0C'], 8 ['1A', '1B', '1C'], 9 ['2A', '2B', '2C'] 10]; 11 12console.log(table(data));
╔════╤════╤════╗
║ 0A │ 0B │ 0C ║
╟────┼────┼────╢
║ 1A │ 1B │ 1C ║
╟────┼────┼────╢
║ 2A │ 2B │ 2C ║
╚════╧════╧════╝
Returns the string in the table format
Parameters:
data: The data to display
any[][]
true
config: Table configuration
object
false
Type: { [type: string]: string }
Default: honeywell
template
Custom borders. The keys are any of:
topLeft
, topRight
, topBody
,topJoin
bottomLeft
, bottomRight
, bottomBody
, bottomJoin
joinLeft
, joinRight
, joinBody
, joinJoin
bodyLeft
, bodyRight
, bodyJoin
headerJoin
1const data = [ 2 ['0A', '0B', '0C'], 3 ['1A', '1B', '1C'], 4 ['2A', '2B', '2C'] 5]; 6 7const config = { 8 border: { 9 topBody: `─`, 10 topJoin: `┬`, 11 topLeft: `┌`, 12 topRight: `┐`, 13 14 bottomBody: `─`, 15 bottomJoin: `┴`, 16 bottomLeft: `└`, 17 bottomRight: `┘`, 18 19 bodyLeft: `│`, 20 bodyRight: `│`, 21 bodyJoin: `│`, 22 23 joinBody: `─`, 24 joinLeft: `├`, 25 joinRight: `┤`, 26 joinJoin: `┼` 27 } 28}; 29 30console.log(table(data, config));
┌────┬────┬────┐
│ 0A │ 0B │ 0C │
├────┼────┼────┤
│ 1A │ 1B │ 1C │
├────┼────┼────┤
│ 2A │ 2B │ 2C │
└────┴────┴────┘
Type: (lineIndex: number, columnCount: number) => boolean
Default: () => true
It is used to tell whether to draw a vertical line. This callback is called for each vertical border of the table.
If the table has n
columns, then the index
parameter is alternatively received all numbers in range [0, n]
inclusively.
1const data = [ 2 ['0A', '0B', '0C'], 3 ['1A', '1B', '1C'], 4 ['2A', '2B', '2C'], 5 ['3A', '3B', '3C'], 6 ['4A', '4B', '4C'] 7]; 8 9const config = { 10 drawVerticalLine: (lineIndex, columnCount) => { 11 return lineIndex === 0 || lineIndex === columnCount; 12 } 13}; 14 15console.log(table(data, config)); 16
╔════════════╗
║ 0A 0B 0C ║
╟────────────╢
║ 1A 1B 1C ║
╟────────────╢
║ 2A 2B 2C ║
╟────────────╢
║ 3A 3B 3C ║
╟────────────╢
║ 4A 4B 4C ║
╚════════════╝
Type: (lineIndex: number, rowCount: number) => boolean
Default: () => true
It is used to tell whether to draw a horizontal line. This callback is called for each horizontal border of the table.
If the table has n
rows, then the index
parameter is alternatively received all numbers in range [0, n]
inclusively.
If the table has n
rows and contains the header, then the range will be [0, n+1]
inclusively.
1const data = [ 2 ['0A', '0B', '0C'], 3 ['1A', '1B', '1C'], 4 ['2A', '2B', '2C'], 5 ['3A', '3B', '3C'], 6 ['4A', '4B', '4C'] 7]; 8 9const config = { 10 drawHorizontalLine: (lineIndex, rowCount) => { 11 return lineIndex === 0 || lineIndex === 1 || lineIndex === rowCount - 1 || lineIndex === rowCount; 12 } 13}; 14 15console.log(table(data, config)); 16
╔════╤════╤════╗
║ 0A │ 0B │ 0C ║
╟────┼────┼────╢
║ 1A │ 1B │ 1C ║
║ 2A │ 2B │ 2C ║
║ 3A │ 3B │ 3C ║
╟────┼────┼────╢
║ 4A │ 4B │ 4C ║
╚════╧════╧════╝
Type: boolean
Default: false
If true
, horizontal lines inside the table are not drawn. This option also overrides the config.drawHorizontalLine
if specified.
1const data = [ 2 ['-rw-r--r--', '1', 'pandorym', 'staff', '1529', 'May 23 11:25', 'LICENSE'], 3 ['-rw-r--r--', '1', 'pandorym', 'staff', '16327', 'May 23 11:58', 'README.md'], 4 ['drwxr-xr-x', '76', 'pandorym', 'staff', '2432', 'May 23 12:02', 'dist'], 5 ['drwxr-xr-x', '634', 'pandorym', 'staff', '20288', 'May 23 11:54', 'node_modules'], 6 ['-rw-r--r--', '1,', 'pandorym', 'staff', '525688', 'May 23 11:52', 'package-lock.json'], 7 ['-rw-r--r--@', '1', 'pandorym', 'staff', '2440', 'May 23 11:25', 'package.json'], 8 ['drwxr-xr-x', '27', 'pandorym', 'staff', '864', 'May 23 11:25', 'src'], 9 ['drwxr-xr-x', '20', 'pandorym', 'staff', '640', 'May 23 11:25', 'test'], 10]; 11 12const config = { 13 singleLine: true 14}; 15 16console.log(table(data, config));
╔═════════════╤═════╤══════════╤═══════╤════════╤══════════════╤═══════════════════╗
║ -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 ║
╚═════════════╧═════╧══════════╧═══════╧════════╧══════════════╧═══════════════════╝
Type: Column[] | { [columnIndex: number]: Column }
Column specific configurations.
Type: number
Default: the maximum cell widths of the column
Column width (excluding the paddings).
1 2const data = [ 3 ['0A', '0B', '0C'], 4 ['1A', '1B', '1C'], 5 ['2A', '2B', '2C'] 6]; 7 8const config = { 9 columns: { 10 1: { width: 10 } 11 } 12}; 13 14console.log(table(data, config));
╔════╤════════════╤════╗
║ 0A │ 0B │ 0C ║
╟────┼────────────┼────╢
║ 1A │ 1B │ 1C ║
╟────┼────────────┼────╢
║ 2A │ 2B │ 2C ║
╚════╧════════════╧════╝
Type: 'center' | 'justify' | 'left' | 'right'
Default: 'left'
Cell content horizontal alignment
1const data = [ 2 ['0A', '0B', '0C', '0D 0E 0F'], 3 ['1A', '1B', '1C', '1D 1E 1F'], 4 ['2A', '2B', '2C', '2D 2E 2F'], 5]; 6 7const config = { 8 columnDefault: { 9 width: 10, 10 }, 11 columns: [ 12 { alignment: 'left' }, 13 { alignment: 'center' }, 14 { alignment: 'right' }, 15 { alignment: 'justify' } 16 ], 17}; 18 19console.log(table(data, config));
╔════════════╤════════════╤════════════╤════════════╗
║ 0A │ 0B │ 0C │ 0D 0E 0F ║
╟────────────┼────────────┼────────────┼────────────╢
║ 1A │ 1B │ 1C │ 1D 1E 1F ║
╟────────────┼────────────┼────────────┼────────────╢
║ 2A │ 2B │ 2C │ 2D 2E 2F ║
╚════════════╧════════════╧════════════╧════════════╝
Type: 'top' | 'middle' | 'bottom'
Default: 'top'
Cell content vertical alignment
1const data = [ 2 ['A', 'B', 'C', 'DEF'], 3]; 4 5const config = { 6 columnDefault: { 7 width: 1, 8 }, 9 columns: [ 10 { verticalAlignment: 'top' }, 11 { verticalAlignment: 'middle' }, 12 { verticalAlignment: 'bottom' }, 13 ], 14}; 15 16console.log(table(data, config));
╔═══╤═══╤═══╤═══╗
║ A │ │ │ D ║
║ │ B │ │ E ║
║ │ │ C │ F ║
╚═══╧═══╧═══╧═══╝
Type: number
Default: 1
The number of whitespaces used to pad the content on the left.
Type: number
Default: 1
The number of whitespaces used to pad the content on the right.
The paddingLeft
and paddingRight
options do not count on the column width. So the column has width = 5
, paddingLeft = 2
and paddingRight = 2
will have the total width is 9
.
1const data = [ 2 ['0A', 'AABBCC', '0C'], 3 ['1A', '1B', '1C'], 4 ['2A', '2B', '2C'] 5]; 6 7const config = { 8 columns: [ 9 { 10 paddingLeft: 3 11 }, 12 { 13 width: 2, 14 paddingRight: 3 15 } 16 ] 17}; 18 19console.log(table(data, config));
╔══════╤══════╤════╗
║ 0A │ AA │ 0C ║
║ │ BB │ ║
║ │ CC │ ║
╟──────┼──────┼────╢
║ 1A │ 1B │ 1C ║
╟──────┼──────┼────╢
║ 2A │ 2B │ 2C ║
╚══════╧══════╧════╝
Type: number
Default: Infinity
The number of characters is which the content will be truncated.
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.
1const data = [ 2 ['Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus pulvinar nibh sed mauris convallis dapibus. Nunc venenatis tempus nulla sit amet viverra.'] 3]; 4 5const config = { 6 columns: [ 7 { 8 width: 20, 9 truncate: 100 10 } 11 ] 12}; 13 14console.log(table(data, config));
╔══════════════════════╗
║ Lorem ipsum dolor si ║
║ t amet, consectetur ║
║ adipiscing elit. Pha ║
║ sellus pulvinar nibh ║
║ sed mauris convall… ║
╚══════════════════════╝
Type: boolean
Default: false
The table
package implements auto text wrapping, i.e., text that has the width greater than the container width will be separated into multiple lines at the nearest space or one of the special characters: \|/_.,;-
.
When wrapWord
is false
:
1const data = [ 2 ['Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus pulvinar nibh sed mauris convallis dapibus. Nunc venenatis tempus nulla sit amet viverra.'] 3]; 4 5const config = { 6 columns: [ { width: 20 } ] 7}; 8 9console.log(table(data, config));
╔══════════════════════╗
║ 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
:
╔══════════════════════╗
║ Lorem ipsum dolor ║
║ sit amet, ║
║ consectetur ║
║ adipiscing elit. ║
║ Phasellus pulvinar ║
║ nibh sed mauris ║
║ convallis dapibus. ║
║ Nunc venenatis ║
║ tempus nulla sit ║
║ amet viverra. ║
╚══════════════════════╝
Type: Column
Default: {}
The default configuration for all columns. Column-specific settings will overwrite the default values.
Type: object
Header configuration.
Deprecated in favor of the new spanning cells API.
The header configuration inherits the most of the column's, except:
content
{string}: the header content.width:
calculate based on the content width automatically.alignment:
center
be default.verticalAlignment:
is not supported.config.border.topJoin
will be config.border.topBody
for prettier.1const data = [ 2 ['0A', '0B', '0C'], 3 ['1A', '1B', '1C'], 4 ['2A', '2B', '2C'], 5 ]; 6 7const config = { 8 columnDefault: { 9 width: 10, 10 }, 11 header: { 12 alignment: 'center', 13 content: 'THE HEADER\nThis is the table about something', 14 }, 15} 16 17console.log(table(data, config));
╔══════════════════════════════════════╗
║ THE HEADER ║
║ This is the table about something ║
╟────────────┬────────────┬────────────╢
║ 0A │ 0B │ 0C ║
╟────────────┼────────────┼────────────╢
║ 1A │ 1B │ 1C ║
╟────────────┼────────────┼────────────╢
║ 2A │ 2B │ 2C ║
╚════════════╧════════════╧════════════╝
Type: SpanningCellConfig[]
Spanning cells configuration.
The configuration should be straightforward: just specify an array of minimal cell configurations including the position of top-left cell and the number of columns and/or rows will be expanded from it.
The content of overlap cells will be ignored to make the data
shape be consistent.
By default, the configuration of column that the top-left cell belongs to will be applied to the whole spanning cell, except:
width
will be summed up of all spanning columns.paddingRight
will be received from the right-most column intentionally.Advances customized column-like styles can be configurable to each spanning cell to overwrite the default behavior.
1const data = [ 2 ['Test Coverage Report', '', '', '', '', ''], 3 ['Module', 'Component', 'Test Cases', 'Failures', 'Durations', 'Success Rate'], 4 ['Services', 'User', '50', '30', '3m 7s', '60.0%'], 5 ['', 'Payment', '100', '80', '7m 15s', '80.0%'], 6 ['Subtotal', '', '150', '110', '10m 22s', '73.3%'], 7 ['Controllers', 'User', '24', '18', '1m 30s', '75.0%'], 8 ['', 'Payment', '30', '24', '50s', '80.0%'], 9 ['Subtotal', '', '54', '42', '2m 20s', '77.8%'], 10 ['Total', '', '204', '152', '12m 42s', '74.5%'], 11]; 12 13const config = { 14 columns: [ 15 { alignment: 'center', width: 12 }, 16 { alignment: 'center', width: 10 }, 17 { alignment: 'right' }, 18 { alignment: 'right' }, 19 { alignment: 'right' }, 20 { alignment: 'right' } 21 ], 22 spanningCells: [ 23 { col: 0, row: 0, colSpan: 6 }, 24 { col: 0, row: 2, rowSpan: 2, verticalAlignment: 'middle'}, 25 { col: 0, row: 4, colSpan: 2, alignment: 'right'}, 26 { col: 0, row: 5, rowSpan: 2, verticalAlignment: 'middle'}, 27 { col: 0, row: 7, colSpan: 2, alignment: 'right' }, 28 { col: 0, row: 8, colSpan: 2, alignment: 'right' } 29 ], 30}; 31 32console.log(table(data, config));
╔══════════════════════════════════════════════════════════════════════════════╗
║ Test Coverage Report ║
╟──────────────┬────────────┬────────────┬──────────┬───────────┬──────────────╢
║ Module │ Component │ Test Cases │ Failures │ Durations │ Success Rate ║
╟──────────────┼────────────┼────────────┼──────────┼───────────┼──────────────╢
║ │ User │ 50 │ 30 │ 3m 7s │ 60.0% ║
║ Services ├────────────┼────────────┼──────────┼───────────┼──────────────╢
║ │ Payment │ 100 │ 80 │ 7m 15s │ 80.0% ║
╟──────────────┴────────────┼────────────┼──────────┼───────────┼──────────────╢
║ Subtotal │ 150 │ 110 │ 10m 22s │ 73.3% ║
╟──────────────┬────────────┼────────────┼──────────┼───────────┼──────────────╢
║ │ User │ 24 │ 18 │ 1m 30s │ 75.0% ║
║ Controllers ├────────────┼────────────┼──────────┼───────────┼──────────────╢
║ │ Payment │ 30 │ 24 │ 50s │ 80.0% ║
╟──────────────┴────────────┼────────────┼──────────┼───────────┼──────────────╢
║ Subtotal │ 54 │ 42 │ 2m 20s │ 77.8% ║
╟───────────────────────────┼────────────┼──────────┼───────────┼──────────────╢
║ Total │ 204 │ 152 │ 12m 42s │ 74.5% ║
╚═══════════════════════════╧════════════╧══════════╧═══════════╧══════════════╝
table
package exports createStream
function used to draw a table and append rows.
Parameter:
table
's, except config.columnDefault.width
and config.columnCount
must be provided.1import { createStream } from 'table'; 2 3const config = { 4 columnDefault: { 5 width: 50 6 }, 7 columnCount: 1 8}; 9 10const stream = createStream(config); 11 12setInterval(() => { 13 stream.write([new Date()]); 14}, 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.
1import { createStream } from 'table'; 2 3import _ from 'lodash'; 4 5const config = { 6 columnDefault: { 7 width: 50 8 }, 9 columnCount: 3, 10 columns: [ 11 { 12 width: 10, 13 alignment: 'right' 14 }, 15 { alignment: 'center' }, 16 { width: 10 } 17 18 ] 19}; 20 21const stream = createStream(config); 22 23let i = 0; 24 25setInterval(() => { 26 let random; 27 28 random = _.sample('abcdefghijklmnopqrstuvwxyz', _.random(1, 30)).join(''); 29 30 stream.write([i++, new Date(), random]); 31}, 500);
Parameter:
'honeywell' | 'norc' | 'ramac' | 'void'
true
You can load one of the predefined border templates using getBorderCharacters
function.
1import { table, getBorderCharacters } from 'table'; 2 3const data = [ 4 ['0A', '0B', '0C'], 5 ['1A', '1B', '1C'], 6 ['2A', '2B', '2C'] 7]; 8 9const config = { 10 border: getBorderCharacters(`name of the template`) 11}; 12 13console.log(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 "borderless 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 pleasant to the eye table, reset the padding and remove the joining rows, e.g.
1 2const output = table(data, { 3 border: getBorderCharacters('void'), 4 columnDefault: { 5 paddingLeft: 0, 6 paddingRight: 1 7 }, 8 drawHorizontalLine: () => false 9 } 10); 11 12console.log(output);
0A 0B 0C
1A 1B 1C
2A 2B 2C
No vulnerabilities found.
Reason
no dangerous workflow patterns detected
Reason
no binaries found in the repo
Reason
packaging workflow detected
Details
Reason
license file detected
Details
Reason
dependency not pinned by hash detected -- score normalized to 5
Details
Reason
Found 10/28 approved changesets -- score normalized to 3
Reason
0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0
Reason
detected GitHub workflow tokens with excessive permissions
Details
Reason
no effort to earn an OpenSSF best practices badge detected
Reason
security policy file not detected
Details
Reason
project is not fuzzed
Details
Reason
branch protection not enabled on development/release branches
Details
Reason
SAST tool is not run on all commits -- score normalized to 0
Details
Reason
28 existing vulnerabilities detected
Details
Score
Last Scanned on 2024-11-25
The Open Source Security Foundation is a cross-industry collaboration to improve the security of open source software (OSS). The Scorecard provides security health metrics for open source projects.
Learn More