Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

columnify

Package Overview
Dependencies
Maintainers
1
Versions
23
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

columnify - npm Package Compare versions

Comparing version 1.3.2 to 1.4.0

columnify.js

211

index.js
"use strict"
var wcwidth = require('./width')
var utils = require('./utils')
var padRight = utils.padRight
var padCenter = utils.padCenter
var padLeft = utils.padLeft
var splitIntoLines = utils.splitIntoLines
var splitLongWords = utils.splitLongWords
var truncateString = utils.truncateString
const wcwidth = require('./width')
const {
padRight,
padCenter,
padLeft,
splitIntoLines,
splitLongWords,
truncateString
} = require('./utils')
var DEFAULT_HEADING_TRANSFORM = function(key) {
return key.toUpperCase()
}
const DEFAULT_HEADING_TRANSFORM = key => key.toUpperCase()
var DEFAULT_DATA_TRANSFORM = function(cell, column, index) {
return cell
}
const DEFAULT_DATA_TRANSFORM = (cell, column, index) => cell
var DEFAULTS = {
const DEFAULTS = Object.freeze({
maxWidth: Infinity,

@@ -31,12 +28,11 @@ minWidth: 0,

dataTransform: DEFAULT_DATA_TRANSFORM
}
})
module.exports = function(items, options) {
module.exports = function(items, options = {}) {
options = options || {}
var columnConfigs = options.config || {}
let columnConfigs = options.config || {}
delete options.config // remove config so doesn't appear on every column.
var maxLineWidth = options.maxLineWidth || Infinity
let maxLineWidth = options.maxLineWidth || Infinity
if (maxLineWidth === 'auto') maxLineWidth = process.stdout.columns || Infinity
delete options.maxLineWidth // this is a line control option, don't pass it to column

@@ -46,3 +42,4 @@

// options.config[columnName] => options => DEFAULTS
options = mixin(options, DEFAULTS)
options = mixin({}, DEFAULTS, options)
options.config = options.config || Object.create(null)

@@ -54,3 +51,3 @@

options.columns = options.columns || options.include // alias include/columns, prefer columns if supplied
var columnNames = options.columns || [] // optional user-supplied columns to include
let columnNames = options.columns || [] // optional user-supplied columns to include

@@ -62,3 +59,3 @@ items = toArray(items, columnNames)

items.forEach(function(item) {
for (var columnName in item) {
for (let columnName in item) {
if (columnNames.indexOf(columnName) === -1) columnNames.push(columnName)

@@ -70,4 +67,4 @@ }

// initialize column defaults (each column inherits from options.config)
var columns = columnNames.reduce(function(columns, columnName) {
var column = Object.create(options)
let columns = columnNames.reduce((columns, columnName) => {
let column = Object.create(options)
columns[columnName] = mixin(column, columnConfigs[columnName])

@@ -78,4 +75,4 @@ return columns

// sanitize column settings
columnNames.forEach(function(columnName) {
var column = columns[columnName]
columnNames.forEach(columnName => {
let column = columns[columnName]
column.name = columnName

@@ -89,5 +86,5 @@ column.maxWidth = Math.ceil(column.maxWidth)

// sanitize data
items = items.map(function(item) {
var result = Object.create(null)
columnNames.forEach(function(columnName) {
items = items.map(item => {
let result = Object.create(null)
columnNames.forEach(columnName => {
// null/undefined -> ''

@@ -109,17 +106,15 @@ result[columnName] = item[columnName] != null ? item[columnName] : ''

// transform data cells
columnNames.forEach(function(columnName) {
var column = columns[columnName]
items = items.map(function(item, index) {
var col = Object.create(column)
columnNames.forEach(columnName => {
let column = columns[columnName]
items = items.map((item, index) => {
let col = Object.create(column)
item[columnName] = column.dataTransform(item[columnName], col, index)
var changedKeys = Object.keys(col)
let changedKeys = Object.keys(col)
// disable default heading transform if we wrote to column.name
if (changedKeys.indexOf('name') !== -1) {
if (column.headingTransform !== DEFAULT_HEADING_TRANSFORM) return
column.headingTransform = function(heading) {return heading}
column.headingTransform = heading => heading
}
changedKeys.forEach(function(key) {
column[key] = col[key]
})
changedKeys.forEach(key => column[key] = col[key])
return item

@@ -130,6 +125,6 @@ })

// add headers
var headers = {}
let headers = {}
if(options.showHeaders) {
columnNames.forEach(function(columnName) {
var column = columns[columnName]
columnNames.forEach(columnName => {
let column = columns[columnName]
headers[columnName] = column.headingTransform(column.name)

@@ -141,7 +136,7 @@ })

// based on length of data in columns
columnNames.forEach(function(columnName) {
var column = columns[columnName]
column.width = items.map(function(item) {
return item[columnName]
}).reduce(function(min, cur) {
columnNames.forEach(columnName => {
let column = columns[columnName]
column.width = items
.map(item => item[columnName])
.reduce((min, cur) => {
return Math.max(min, Math.min(column.maxWidth, Math.max(column.minWidth, wcwidth(cur))))

@@ -152,5 +147,5 @@ }, 0)

// split long words so they can break onto multiple lines
columnNames.forEach(function(columnName) {
var column = columns[columnName]
items = items.map(function(item) {
columnNames.forEach(columnName => {
let column = columns[columnName]
items = items.map(item => {
item[columnName] = splitLongWords(item[columnName], column.width, column.truncateMarker)

@@ -162,6 +157,6 @@ return item

// wrap long lines. each item is now an array of lines.
columnNames.forEach(function(columnName) {
var column = columns[columnName]
items = items.map(function(item, index) {
var cell = item[columnName]
columnNames.forEach(columnName => {
let column = columns[columnName]
items = items.map((item, index) => {
let cell = item[columnName]
item[columnName] = splitIntoLines(cell, column.width)

@@ -171,6 +166,6 @@

if (column.truncate && item[columnName].length > 1) {
item[columnName] = splitIntoLines(cell, column.width - wcwidth(column.truncateMarker))
var firstLine = item[columnName][0]
if (!endsWith(firstLine, column.truncateMarker)) item[columnName][0] += column.truncateMarker
item[columnName] = item[columnName].slice(0, 1)
item[columnName] = splitIntoLines(cell, column.width - wcwidth(column.truncateMarker))
let firstLine = item[columnName][0]
if (!endsWith(firstLine, column.truncateMarker)) item[columnName][0] += column.truncateMarker
item[columnName] = item[columnName].slice(0, 1)
}

@@ -182,9 +177,9 @@ return item

// recalculate column widths from truncated output/lines
columnNames.forEach(function(columnName) {
var column = columns[columnName]
column.width = items.map(function(item) {
return item[columnName].reduce(function(min, cur) {
columnNames.forEach(columnName => {
let column = columns[columnName]
column.width = items.map(item => {
return item[columnName].reduce((min, cur) => {
return Math.max(min, Math.min(column.maxWidth, Math.max(column.minWidth, wcwidth(cur))))
}, 0)
}).reduce(function(min, cur) {
}).reduce((min, cur) => {
return Math.max(min, Math.min(column.maxWidth, Math.max(column.minWidth, cur)))

@@ -195,11 +190,11 @@ }, 0)

var rows = createRows(items, columns, columnNames, options.paddingChr) // merge lines into rows
let rows = createRows(items, columns, columnNames, options.paddingChr) // merge lines into rows
// conceive output
return rows.reduce(function(output, row) {
return output.concat(row.reduce(function(rowOut, line) {
return rows.reduce((output, row) => {
return output.concat(row.reduce((rowOut, line) => {
return rowOut.concat(line.join(options.columnSplitter))
}, []))
}, []).map(function(line) {
return truncateString(line, maxLineWidth)
}).join(options.spacing)
}, [])
.map(line => truncateString(line, maxLineWidth))
.join(options.spacing)
}

@@ -217,14 +212,14 @@

function createRows(items, columns, columnNames, paddingChr) {
return items.map(function(item) {
var row = []
var numLines = 0
columnNames.forEach(function(columnName) {
return items.map(item => {
let row = []
let numLines = 0
columnNames.forEach(columnName => {
numLines = Math.max(numLines, item[columnName].length)
})
// combine matching lines of each rows
for (var i = 0; i < numLines; i++) {
for (let i = 0; i < numLines; i++) {
row[i] = row[i] || []
columnNames.forEach(function(columnName) {
var column = columns[columnName]
var val = item[columnName][i] || '' // || '' ensures empty columns get padded
columnNames.forEach(columnName => {
let column = columns[columnName]
let val = item[columnName][i] || '' // || '' ensures empty columns get padded
if (column.align === 'right') row[i].push(padLeft(val, column.width, paddingChr))

@@ -240,18 +235,46 @@ else if (column.align === 'center' || column.align === 'centre') row[i].push(padCenter(val, column.width, paddingChr))

/**
* Generic source->target mixin.
* Copy properties from `source` into `target` if target doesn't have them.
* Destructive. Modifies `target`.
* Object.assign
*
* @param target Object target for mixin properties.
* @param source Object source of mixin properties.
* @return Object `target` after mixin applied.
* @return Object Object with properties mixed in.
*/
function mixin(target, source) {
source = source || {}
for (var key in source) {
if (target.hasOwnProperty(key)) continue
target[key] = source[key]
function mixin(...args) {
if (Object.assign) return Object.assign(...args)
return ObjectAssign(...args)
}
function ObjectAssign(target, firstSource) {
"use strict";
if (target === undefined || target === null)
throw new TypeError("Cannot convert first argument to object");
var to = Object(target);
var hasPendingException = false;
var pendingException;
for (var i = 1; i < arguments.length; i++) {
var nextSource = arguments[i];
if (nextSource === undefined || nextSource === null)
continue;
var keysArray = Object.keys(Object(nextSource));
for (var nextIndex = 0, len = keysArray.length; nextIndex < len; nextIndex++) {
var nextKey = keysArray[nextIndex];
try {
var desc = Object.getOwnPropertyDescriptor(nextSource, nextKey);
if (desc !== undefined && desc.enumerable)
to[nextKey] = nextSource[nextKey];
} catch (e) {
if (!hasPendingException) {
hasPendingException = true;
pendingException = e;
}
}
}
if (hasPendingException)
throw pendingException;
}
return target
return to;
}

@@ -266,3 +289,3 @@

position = position - searchString.length;
var lastIndex = target.lastIndexOf(searchString);
let lastIndex = target.lastIndexOf(searchString);
return lastIndex !== -1 && lastIndex === position;

@@ -274,5 +297,5 @@ }

if (Array.isArray(items)) return items
var rows = []
for (var key in items) {
var item = {}
let rows = []
for (let key in items) {
let item = {}
item[columnNames[0] || 'key'] = key

@@ -279,0 +302,0 @@ item[columnNames[1] || 'value'] = items[key]

{
"name": "columnify",
"version": "1.3.2",
"version": "1.4.0",
"description": "Render data in text columns. supports in-column text-wrap.",
"main": "index.js",
"main": "columnify.js",
"scripts": {
"pretest": "npm prune",
"test": "tape test/*.js | tap-spec",
"bench": "npm test && node bench"
"test": "make prepublish && tape test/*.js | tap-spec",
"bench": "npm test && node bench",
"prepublish": "make prepublish"
},

@@ -14,2 +15,3 @@ "author": "Tim Oxley",

"devDependencies": {
"6to5": "^2.13.7",
"chalk": "^0.5.1",

@@ -16,0 +18,0 @@ "tap-spec": "^2.1.1",

@@ -39,3 +39,2 @@ # columnify

```javascript
var data = {

@@ -104,11 +103,54 @@ "commander@0.6.1": 1,

### Wrapping Column Cells
### Filtering & Ordering Columns
You can define the maximum width before wrapping for individual cells in
columns. Minimum width is also supported. Wrapping will happen at word
boundaries. Empty cells or those which do not fill the max/min width
will be padded with spaces.
By default, all properties are converted into columns, whether or not
they exist on every object or not.
To explicitly specify which columns to include, and in which order,
supply a "columns" or "include" array ("include" is just an alias).
```javascript
var data = [{
name: 'module1',
description: 'some description',
version: '0.0.1',
}, {
name: 'module2',
description: 'another description',
version: '0.2.0',
}]
var columns = columnify(data, {
columns: ['name', 'version']
})
console.log(columns)
```
#### Output:
```
NAME VERSION
module1 0.0.1
module2 0.2.0
```
## Global and Per Column Options
You can set a number of options at a global level (ie. for all columns) or on a per column basis.
Set options on a per column basis by using the `config` option to specify individual columns:
```javascript
var columns = columnify(data, {
optionName: optionValue,
config: {
columnName: {optionName: optionValue},
columnName: {optionName: optionValue},
}
})
```
### Maximum and Minimum Column Widths
As with all options, you can define the `maxWidth` and `minWidth` globally, or for specified columns. By default, wrapping will happen at word boundaries. Empty cells or those which do not fill the `minWidth` will be padded with spaces.
```javascript
var columns = columnify([{

@@ -122,2 +164,7 @@ name: 'mod1',

version: '0.2.0',
}], {
minWidth: 20,
config: {
description: {maxWidth: 30}
}
})

@@ -127,16 +174,28 @@

```
#### Output:
```
NAME DESCRIPTION VERSION
mod1 some description which happens 0.0.1
to be far larger than the max
module-two another description larger 0.2.0
than the max
NAME DESCRIPTION VERSION
mod1 some description which happens 0.0.1
to be far larger than the max
module-two another description larger 0.2.0
than the max
```
### Truncating Column Cells
#### Maximum Line Width
You can set a hard maximum line width using the `maxLineWidth` option.
Beyond this value data is unceremoniously truncated with no truncation
marker.
This can either be a number or 'auto' to set the value to the width of
stdout.
Setting this value to 'auto' prevent TTY-imposed line-wrapping when
lines exceed the screen width.
#### Truncating Column Cells Instead of Wrapping
You can disable wrapping and instead truncate content at the maximum
column width. Truncation respects word boundaries. A truncation marker,
`…` will appear next to the last word in any truncated line.
column width by using the `truncate` option. Truncation respects word boundaries. A truncation marker, `…`, will appear next to the last word in any truncated line.

@@ -162,39 +221,5 @@ ```javascript

### Filtering & Ordering Columns
By default, all properties are converted into columns, whether or not
they exist on every object or not.
To explicitly specify which columns to include, and in which order,
supply a "columns" or "include" array ("include" is just an alias).
```javascript
var data = [{
name: 'module1',
description: 'some description',
version: '0.0.1',
}, {
name: 'module2',
description: 'another description',
version: '0.2.0',
}]
var columns = columnify(data, {
columns: ['name', 'version'] // note description not included
})
console.log(columns)
```
#### Output:
```
NAME VERSION
module1 0.0.1
module2 0.2.0
```
## Other Configuration Options
### Align Right/Center
You can set the alignment of the column data by using the `align` option.

@@ -219,7 +244,9 @@ ```js

Align Center works in a similar way.
`align: 'center'` works in a similar way.
### Padding
### Padding Character
Set a character to fill whitespace within columns with the `paddingChr` option.
```js

@@ -241,3 +268,3 @@ var data = {

### Preserve existing newlines
### Preserve Existing Newlines

@@ -294,3 +321,3 @@ By default, `columnify` sanitises text by replacing any occurance of 1 or more whitespace characters with a single space.

You can change the truncation marker to something other than the default
`…`.
`…` by using the `truncateMarker` option.

@@ -320,6 +347,5 @@ ```javascript

If your columns need some bling, you can split columns with custom
characters.
characters by using the `columnSplitter` option.
```javascript
var columns = columnify(data, {

@@ -338,2 +364,44 @@ columnSplitter: ' | '

### Control Header Display
Control whether column headers are displayed by using the `showHeaders` option.
```javascript
var columns = columnify(data, {
showHeaders: false
})
```
### Transforming Column Data and Headers
If you need to modify the presentation of column content or heading content there are two useful options for doing that: `dataTransform` and `headerTransform`. Both of these take a function and need to return a valid string.
```javascript
var columns = columnify([{
name: 'mod1',
description: 'SOME DESCRIPTION TEXT.'
}, {
name: 'module-two',
description: 'SOME SLIGHTLY LONGER DESCRIPTION TEXT.'
}], {
dataTransform: function(data) {
return data.toLowerCase()
},
config: {
name: {
headingTransform: function(heading) {
heading = "module " + heading
return "*" + heading.toUpperCase() + "*"
}
}
}
})
```
#### Output:
```
*MODULE NAME* DESCRIPTION
mod1 some description text.
module-two some slightly longer description text.
```
## Multibyte Character Support

@@ -340,0 +408,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