Socket
Socket
Sign inDemoInstall

tty-table

Package Overview
Dependencies
Maintainers
1
Versions
89
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

tty-table - npm Package Compare versions

Comparing version 2.8.12 to 3.0.0

27

package.json
{
"name": "tty-table",
"version": "2.8.12",
"version": "3.0.0",
"description": "Node cli table",
"main": "src/main.js",
"engines": {
"node": ">=8.16.0"
"node": ">=12.0.0"
},

@@ -22,3 +22,5 @@ "bin": {

"test": "npx mocha",
"save-tests": "npx grunt st",
"report-to-coveralls": "npx nyc report --reporter=text-lcov | npx coveralls",
"report-to-cover-io": "npx nyc report --reporter=text-lcov > coverage.lcov && ./node_modules/.bin/codecov -t ffe0f46d-c939-4302-b199-0f2de3e8c18a",
"save-tests": "node npm_scripts/save-tests.js",
"lint": "npx eslint adapters/* src/*",

@@ -55,3 +57,3 @@ "lint-fix": "npx eslint adapters/* src/* --fix",

"kleur": "^3.0.3",
"smartwrap": "^1.2.3",
"smartwrap": "^1.2.5",
"strip-ansi": "^6.0.0",

@@ -70,6 +72,6 @@ "wcwidth": "^1.0.1",

"browserify": "^16.5.0",
"browserify-banner": "^1.0.14",
"chai": "^4.2.0",
"codecov": "^3.6.5",
"commander": "^4.1.1",
"doctoc": "^1.4.0",
"coveralls": "^3.0.9",
"eslint": "^6.8.0",

@@ -81,11 +83,18 @@ "glob": "^7.1.4",

"grunt-contrib-watch": "^1.1.0",
"grunt-jsdoc": "^2.4.0",
"grunt-shell": "^3.0.1",
"husky": "^4.2.1",
"jsdoc-to-markdown": "^5.0.0",
"mocha": "^6.1.4",
"mocha-lcov-reporter": "^1.3.0",
"nyc": "^15.0.0",
"orgy": "^2.2.1",
"rollup": "^1.31.1"
}
},
"nyc": {
"all": false,
"include": [
"src/*.js",
"adapters/*.js"
]
},
"defaultTestColumns": 90
}

@@ -1,5 +0,4 @@

# tty-table 电传打字台
# tty-table 端子台
[![Build Status](https://travis-ci.org/tecfu/tty-table.svg?branch=master)](https://travis-ci.org/tecfu/tty-table) [![NPM version](https://badge.fury.io/js/tty-table.svg)](http://badge.fury.io/js/tty-table)
[![Build Status](https://travis-ci.org/tecfu/tty-table.svg?branch=master)](https://travis-ci.org/tecfu/tty-table) [![NPM version](https://badge.fury.io/js/tty-table.svg)](http://badge.fury.io/js/tty-table) [![Coverage Status](https://coveralls.io/repos/github/tecfu/tty-table/badge.svg?branch=master)](https://coveralls.io/github/tecfu/tty-table?branch=master)
---

@@ -37,8 +36,8 @@

- [examples/browser-example.html](examples/browser-example.html)
- [demo: jsfiddle](https://jsfiddle.net/6hz1a9cs/3/)
- [demo: plinkr](https://plnkr.co/edit/iQn9xn5yCY4NUkXRF87o?p=preview)
- [source: examples/browser-example.html](examples/browser-example.html)
![Browser Console Example](https://user-images.githubusercontent.com/7478359/74614563-cbcaff00-50e6-11ea-9101-5457497696b8.jpg "tty-table in the browser console")
[Working Example in Browser](https://cdn.rawgit.com/tecfu/tty-table/master/examples/browser-example.html)
<br/>

@@ -216,8 +215,6 @@ <br/>

```html
import Table from './dist/tty-table.esm.js'
// other options:
// let Table = require('tty-table') // dist/tty-table.cjs.js
// let Table = TTY_Table; // dist/tty-table.umd.js
```js
import Table from 'https://cdn.jsdelivr.net/gh/tecfu/tty-table/dist/tty-table.esm.js'
let Table = require('tty-table') // https://cdn.jsdelivr.net/gh/tecfu/tty-table/dist/tty-table.cjs.js
let Table = TTY_Table; // https://cdn.jsdelivr.net/gh/tecfu/tty-table/dist/tty-table.umd.js
```

@@ -232,2 +229,6 @@

```sh
$ npm run coverage
```
## Saving the output of new unit tests

@@ -234,0 +235,0 @@

@@ -0,1 +1,2 @@

// @TODO split defaults into table and cell settings
const defaults = {

@@ -38,2 +39,3 @@ borderCharacters: {

headerColor: "yellow",
isNull: false, // undocumented cell setting
marginLeft: 2,

@@ -40,0 +42,0 @@ marginTop: 1,

@@ -6,54 +6,2 @@ const defaults = require("./defaults.js")

/**
* @class Table
* @param {array} header - [See example](#example-usage)
* @param {object} header.column - Column options
* @param {string} header.column.alias - Alternate header column name
* @param {string} header.column.align - default: "center"
* @param {string} header.column.color - default: terminal default color
* @param {string} header.column.footerAlign - default: "center"
* @param {string} header.column.footerColor - default: terminal default color
* @param {function(cellValue, columnIndex, rowIndex, rowData, inputData)</code} header.column.formatter - Runs a callback on each cell value in the parent column
* @param {string} header.column.headerAlign - default: "center"
* @param {string} header.column.headerColor - default: terminal's default color
* @param {number} header.column.marginLeft - default: 0
* @param {number} header.column.marginTop - default: 0
* @param {string|number} header.column.width - default: "auto"
* @param {number} header.column.paddingBottom - default: 0
* @param {number} header.column.paddingLeft - default: 1
* @param {number} header.column.paddingRight - default: 1
* @param {number} header.column.paddingTop - default: 0
*
* @param {array} rows - [See example](#example-usage)
*
* @param {object} options - Table options
* @param {string} options.borderStyle - default: "solid". options: "solid", "dashed", "none"
* @param {object} options.borderCharacters - [See @note](#note)
* @param {string} options.borderColor - default: terminal's default color
* @param {boolean} options.compact - default: false
* Removes horizontal lines when true.
* @param {mixed} options.defaultErrorValue - default: '�'
* @param {mixed} options.defaultValue - default: '?'
* @param {boolean} options.errorOnNull - default: false
* @param {mixed} options.truncate - default: false
* <br/>
* When this property is set to a string, cell contents will be truncated by that string instead of wrapped when they extend beyond of the width of the cell.
* <br/>
* For example if:
* <br/>
* <code>"truncate":"..."</code>
* <br/>
* the cell will be truncated with "..."
* @returns {Table}
* @example
* ```js
* let Table = require('tty-table');
* let t1 = Table(header,rows,options);
* console.log(t1.render());
* ```
*
*/
const Factory = function(paramsArr) {

@@ -118,3 +66,3 @@

// For "deep" copy, use JSON.parse
// for "deep" copy, use JSON.parse
const cloneddefaults = JSON.parse(JSON.stringify(defaults))

@@ -135,3 +83,3 @@ let config = Object.assign({}, cloneddefaults, options)

Object.keys(obj).forEach(function(key) {
obj[key] = Style.color(obj[key], config.borderColor)
obj[key] = Style.style(obj[key], config.borderColor)
})

@@ -187,4 +135,9 @@ return obj

module.exports = function() {
let Table = function() {
return new Factory(arguments)
}
Table.resetStyle = Style.resetStyle
Table.style = Style.styleEachChar
module.exports = Table

@@ -6,9 +6,85 @@ const stripAnsi = require("strip-ansi")

module.exports.calculateLength = line => {
// return stripAnsi(line.replace(/[^\x00-\xff]/g,'XX')).length
return wcwidth(stripAnsi(line))
const addPadding = (config, width) => {
return width + config.paddingLeft + config.paddingRight
}
module.exports.wrapCellContent = (
/**
* Returns the widest cell give a collection of rows
*
* @param object columnOptions
* @param array rows
* @param integer columnIndex
* @returns string
*/
const getMaxLength = (columnOptions, rows, columnIndex) => {
let iterable
// add a row that contains the header value, so we use that width too
if(typeof columnOptions === "object" && columnOptions.value) {
iterable = rows.slice()
let z = new Array(iterable[0].length) // create a new empty row
z[columnIndex] = columnOptions.value.toString()
iterable.push(z)
} else {
// no header value, just use rows to derive max width
iterable = rows
}
// iterable.forEach( row => {
// if(row[columnIndex] && stripAnsi(row[columnIndex].toString()).length > widest) {
// widest = wcwidth(row[columnIndex].toString())
// }
// })
let widest = iterable.reduce((prev, row) => {
if(row[columnIndex]) {
let width = wcwidth(stripAnsi(row[columnIndex].toString()))
return ( width > prev) ? width : prev
}
return prev
}, 0)
return widest
}
/**
* Get total width available to this table instance
*
*
*/
const getAvailableWidth = config => {
if (process && ((process.stdout && process.stdout.columns) || (process.env && process.env.COLUMNS))) {
// forked calls that do not inherit process.stdout must use process.env
let viewport = (process.stdout && process.stdout.columns) ? process.stdout.columns : process.env.COLUMNS
viewport = viewport - config.marginLeft
// table width fixed
if (config.width !== "auto" && /^\d{1,2}$/.test(config.width)) return config.width
// table width percentage of (viewport less margin)
if (config.width !== "auto" && /^\d{1,2}%$/.test(config.width)) {
return (config.width.slice(0, -1) * .01) * viewport
}
// table width equals viewport less margin
return viewport
}
// browser
if (typeof window !== "undefined") return window.innerWidth // eslint-disable-line
throw new Error ("Cannot auto discover available table width. Set table `width` option or export the environment variable COLUMNS")
}
module.exports.getStringLength = string => {
// stripAnsi(string.replace(/[^\x00-\xff]/g,'XX')).length
return wcwidth(stripAnsi(string))
}
module.exports.wrapCellText = (
config,

@@ -80,3 +156,3 @@ cellValue,

const lineLength = exports.calculateLength(line)
const lineLength = exports.getStringLength(line)

@@ -125,3 +201,3 @@ // alignment

if(maxWidth < stringWidth) {
// @todo give use option to decide if they want to break words on wrapping
// @TODO give user option to decide if they want to break words on wrapping
string = smartwrap(string, {

@@ -150,37 +226,9 @@ width: maxWidth - cellOptions.truncate.length,

/**
* Returns the widest cell give a collection of rows
*
* @param array rows
* @param integer columnIndex
* @returns integer
*/
module.exports.inferColumnWidth = (columnOptions, rows, columnIndex) => {
module.exports.getColumnWidths = (config, rows) => {
let iterable
let widest = 0
const availableWidth = getAvailableWidth(config)
// add a row that contains the header value, so we use that width too
if(typeof columnOptions === "object" && columnOptions.value) {
iterable = rows.slice()
let z = new Array(iterable[0].length) // create a new empty row
z[columnIndex] = columnOptions.value.toString()
iterable.push(z)
} else {
// no header value, just use rows to derive max width
iterable = rows
}
// array of spaces that cant be proportionately reduced for each row
const nonResizableRowSpaces = []
iterable.forEach( row => {
if(row[columnIndex] && row[columnIndex].toString().length > widest) {
widest = wcwidth(row[columnIndex].toString())
}
})
return widest
}
module.exports.getColumnWidths = (config, rows) => {
// iterate over the header if we have it, iterate over the first row

@@ -193,23 +241,27 @@ // if we do not (to step through the correct number of columns)

let result
nonResizableRowSpaces[columnIndex] = 0 // track non resizable space for row
switch(true) {
// column width specified in header
case(typeof column === "object" && typeof column.width === "number"):
// column width is specified in column header
case(typeof column === "object" && (/^\d{1,2}$/.test(column.width))):
result = column.width
break
// global column width set in config
case(config.width && config.width !== "auto"):
result = config.width
// column width is a percentage of table width specified in column header
case(typeof column === "object" && (/^\d{1,2}%$/.test(column.width))):
result = (column.width.slice(0, -1) * .01) * availableWidth
result = addPadding(config, result)
break
// 'auto' sets column width to its longest value in the initial data set
default:
// 'auto' sets column width to longest value in initial data set
let columnOptions = (config.table.header[0][columnIndex])
? config.table.header[0][columnIndex] : {}
let measurableRows = (rows.length) ? rows : config.table.header[0]
result = exports.inferColumnWidth(columnOptions, measurableRows, columnIndex)
result = getMaxLength(columnOptions, measurableRows, columnIndex)
// add spaces for padding if not centered
result = result + config.paddingLeft + config.paddingRight
// @TODO test with if not centered conditional
result = addPadding(config, result)
}

@@ -224,14 +276,17 @@

// calculate sum of all column widths (including marginLeft)
let totalWidth = widths.reduce((prev, curr) => prev + curr)
let totalWidth = widths.reduce((prev, current) => prev + current)
// if sum of all widths exceeds viewport, resize proportionately to fit
if(process && process.stdout && totalWidth > process.stdout.columns) {
// recalculate proportionately to fit
let prop = (process.stdout.columns - config.marginLeft) / totalWidth
if(totalWidth > availableWidth) {
let prop = availableWidth / totalWidth
let relativeWidths
let totalRelativeWidths
prop = prop.toFixed(2) - 0.01
prop = prop.toFixed(2) - 0.01 // this wont be exact fit, but keeps us safe
// when process.stdout.columns is 0, width will be negative
// when prop < 0 column cant be resized and totalWidth must overflow viewport
if (prop > 0) {
widths = widths.map(value => Math.floor(prop * value))
relativeWidths = widths.map(value => Math.floor(prop * value))
totalRelativeWidths = relativeWidths.reduce((prev, current) => prev + current)
widths = (totalRelativeWidths < totalWidth) ? relativeWidths : widths
}

@@ -238,0 +293,0 @@ }

@@ -21,3 +21,3 @@ const Style = require("./style.js")

const constructorType = exports.getConstructorGeometry(inputData[0] || [], config)
const rows = exports.coerceConstructor(config, inputData, constructorType)
const rows = exports.coerceConstructorGeometry(config, inputData, constructorType)

@@ -44,3 +44,3 @@ // when streaming values to tty-table, we don't want column widths to change

case (config.showHeader === true): // explicitly true, show
case (!!config.table.header[0].find(obj => obj.value)): // atleast one named column, show
case (!!config.table.header[0].find(obj => obj.value || obj.alias)): // atleast one named column, show
sections.header = config.table.header.map(row => {

@@ -153,4 +153,3 @@ return exports.buildRow(config, row, "header", null, rows, inputData)

// tag row as empty if empty
// (used) for compact tables
// tag row as empty if empty, used for `compact` option
if(row.length === 0 && config.compact) {

@@ -243,2 +242,4 @@ row.empty = true

cellValue = (config.errorOnNull) ? config.defaultErrorValue : config.defaultValue
// @TODO add to cell defaults
cellOptions.isNull = true
break

@@ -251,4 +252,4 @@

case(typeof cell === "function"):
cellValue = cell.bind({ style: Style.color })(
cellValue,
cellValue = cell.bind({ style: Style.style })(
(!cellOptions.isNull) ? cellValue : "",
columnIndex,

@@ -269,4 +270,4 @@ rowIndex,

cellValue = cellOptions.formatter
.bind({ style: Style.color })(
cellValue,
.bind({ style: Style.style })(
(!cellOptions.isNull) ? cellValue : "",
columnIndex,

@@ -284,3 +285,3 @@ rowIndex,

// textwrap cellValue
let wrapObj = Format.wrapCellContent(config, cellValue, columnIndex, cellOptions, rowType)
let wrapObj = Format.wrapCellText(config, cellValue, columnIndex, cellOptions, rowType)

@@ -331,3 +332,3 @@ // return as array of lines

*/
module.exports.coerceConstructor = (config, rows, constructorType) => {
module.exports.coerceConstructorGeometry = (config, rows, constructorType) => {

@@ -386,17 +387,17 @@ let output = []

// assumes all rows are same length
module.exports.verticalizeMatrix = (config, inputArray) => {
// grow to # arrays equal to number of columns in input array
let outputArray = []
let headers = config.table.columns
// create a row for each heading, and prepend the row
// with the heading name
headers.forEach(name => outputArray.push([name]))
inputArray.forEach(row => {
row.forEach((element, index) => outputArray[index].push(element))
})
return outputArray
}
// module.exports.verticalizeMatrix = (config, inputArray) => {
//
// // grow to # arrays equal to number of columns in input array
// let outputArray = []
// let headers = config.table.columns
//
// // create a row for each heading, and prepend the row
// // with the heading name
// headers.forEach(name => outputArray.push([name]))
//
// inputArray.forEach(row => {
// row.forEach((element, index) => outputArray[index].push(element))
// })
//
// return outputArray
// }
const kleur = require("kleur")
const stripAnsi = require("strip-ansi")
module.exports.color = (str, ...colors) => {
return colors.reduce(function(input, color) {
module.exports.style = (str, ...colors) => {
let out = colors.reduce(function(input, color) {
return kleur[color](input)
}, str)
return out
}
module.exports.styleEachChar = (str, ...colors) => {
// strip existing ansi chars so we dont loop them
// @ TODO create a really clever workaround so that you can accrete styles
let chars = [...stripAnsi(str)]
// style each character
let out = chars.reduce((prev, current) => {
let coded = colors.reduce((input, color) => {
return kleur[color](input)
}, current)
return prev + coded
}, "")
return out
}
module.exports.resetStyle = (str) => {
return stripAnsi(str)
}
module.exports.colorizeCell = (str, cellOptions, rowType) => {

@@ -28,3 +53,3 @@

if (color) {
str = exports.color(str, color)
str = exports.style(str, color)
}

@@ -31,0 +56,0 @@

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc