Socket
Socket
Sign inDemoInstall

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 0.0.4 to 0.1.0

test/data-transform-expected.txt

138

index.js
"use strict"
module.exports = function(items, options) {
var utils = require('./utils')
var padRight = utils.padRight
var splitIntoLines = utils.splitIntoLines
var splitLongWords = utils.splitLongWords
// defaults
options = options || Object.create(null)
var defaultColumn = options.defaultColumn || {
maxWidth: Infinity,
minWidth: 0
var DEFAULTS = {
maxWidth: Infinity,
minWidth: 0,
columnSplitter: ' ',
truncate: false,
truncateMarker: '…',
headingTransform: function(key) {
return key.toUpperCase()
},
dataTransform: function(cell, column, index) {
return cell
}
}
defaultColumn.maxWidth = defaultColumn.maxWidth || Infinity
defaultColumn.minWidth = defaultColumn.minWidth || 0
options.columnSplitter = options.columnSplitter || ' '
module.exports = function(items, options) {
if (typeof options.truncate !== 'string') {
options.truncate = options.truncate ? '…' : false
}
options = options || {}
options.spacing = options.spacing || '\n'
var columnConfigs = options.config || {}
delete options.config // remove config so doesn't appear on every column.
options.widths = options.widths || Object.create(null)
// Option defaults inheritance:
// options.config[columnName] => options => DEFAULTS
options = mixin(options, DEFAULTS)
options.config = options.config || Object.create(null)
var columnNames = options.columns || []
options.spacing = options.spacing || '\n' // probably useless
// if not suppled column names, automatically determine columns from data
var columnNames = options.include || [] // optional user-supplied columns to include
// if not suppled column names, automatically determine columns from data keys
if (!columnNames.length) {

@@ -35,14 +47,15 @@ items.forEach(function(item) {

// initialize each column
// initialize column defaults (each column inherits from options.config)
var columns = columnNames.reduce(function(columns, columnName) {
columns[columnName] = {}
var column = Object.create(options)
columns[columnName] = mixin(column, columnConfigs[columnName])
return columns
}, Object.create(null))
// set column defaults
// sanitize column settings
columnNames.forEach(function(columnName) {
var column = columns[columnName]
var width = options.widths[columnName] || defaultColumn
column.maxWidth = width.maxWidth || defaultColumn.maxWidth || Infinity
column.minWidth = width.minWidth || defaultColumn.minWidth || 0
column.maxWidth = Math.ceil(column.maxWidth)
column.minWidth = Math.ceil(column.minWidth)
column.truncate = !!column.truncate
})

@@ -64,6 +77,16 @@

// transform data cells
columnNames.forEach(function(columnName) {
var column = columns[columnName]
items = items.map(function(item, index) {
item[columnName] = column.dataTransform(item[columnName], column, index)
return item
})
})
// add headers
var headers = {}
columnNames.forEach(function(columnName) {
headers[columnName] = columnName.toUpperCase()
var column = columns[columnName]
headers[columnName] = column.headingTransform(columnName)
})

@@ -83,6 +106,15 @@ items.unshift(headers)

// wrap long lines
// split long words so they can break onto multiple lines
columnNames.forEach(function(columnName) {
var column = columns[columnName]
items = items.map(function(item) {
item[columnName] = splitLongWords(item[columnName], column.width, column.truncateMarker)
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]

@@ -92,5 +124,6 @@ item[columnName] = splitIntoLines(cell, column.width)

// if truncating required, only include first line + add truncation char
if (options.truncate && item[columnName].length > 1) {
item[columnName] = splitIntoLines(cell, column.width - options.truncate.length)
item[columnName][0] += options.truncate
if (column.truncate && item[columnName].length > 1) {
item[columnName] = splitIntoLines(cell, column.width - column.truncateMarker.length)
var firstLine = item[columnName][0]
if (!endsWith(firstLine, column.truncateMarker)) item[columnName][0] += column.truncateMarker
item[columnName] = item[columnName].slice(0, 1)

@@ -102,3 +135,3 @@ }

// recalculate column widths from truncated output
// recalculate column widths from truncated output/lines
columnNames.forEach(function(columnName) {

@@ -115,3 +148,3 @@ var column = columns[columnName]

var rows = createRows(items, columns, columnNames)
var rows = createRows(items, columns, columnNames) // merge lines into rows

@@ -156,38 +189,29 @@ // conceive output

/**
* Pad `str` up to total length `max` with `chr`.
* If `str` is longer than `max`, padRight will return `str` unaltered.
* Generic source->target mixin.
* Copy properties from `source` into `target` if target doesn't have them.
* Destructive. Modifies `target`.
*
* @param String str string to pad
* @param Number max total length of output string
* @param String chr optional. Character to pad with. default: ' '
* @return String padded str
* @param target Object target for mixin properties.
* @param source Object source of mixin properties.
* @return Object `target` after mixin applied.
*/
function padRight(str, max, chr) {
var length = 1 + max - str.length
if (length <= 0) return str
return str + Array.apply(null, {length: length})
.join(chr || ' ')
function mixin(target, source) {
source = source || {}
for (var key in source) {
if (target.hasOwnProperty(key)) continue
target[key] = source[key]
}
return target
}
/**
* Split a String `str` into lines of maxiumum length `max`.
* Splits on word boundaries.
*
* @param String str string to split
* @param Number max length of each line
* @return Array Array containing lines.
* Adapted from String.prototype.endsWith polyfill.
*/
function splitIntoLines(str, max) {
return str.trim().split(' ').reduce(function(lines, word) {
var line = lines[lines.length - 1]
if (line && line.join(' ').length + word.length < max) {
lines[lines.length - 1].push(word) // add to line
}
else lines.push([word]) // new line
return lines
}, []).map(function(l) {
return l.join(' ')
})
function endsWith(target, searchString, position) {
position = position || target.length;
position = position - searchString.length;
var lastIndex = target.lastIndexOf(searchString);
return lastIndex !== -1 && lastIndex === position;
}
{
"name": "columnify",
"version": "0.0.4",
"description": "Render data in text columns, with in-column text-wrap.",
"version": "0.1.0",
"description": "Render data in text columns, supports in-column text-wrap.",
"main": "index.js",

@@ -26,3 +26,6 @@ "directories": {

"ansi",
"wrap"
"console",
"terminal",
"wrap",
"table"
],

@@ -29,0 +32,0 @@ "bugs": {

@@ -91,3 +91,3 @@ # columnify

truncate: true,
widths: {
config: {
description: {

@@ -108,2 +108,3 @@ maxWidth: 20

### Custom Truncation Marker

@@ -116,3 +117,4 @@

var columns = columnify(data, {
truncate: '>',
truncate: true,
truncateMarker: '>',
widths: {

@@ -159,3 +161,3 @@ description: {

To explicitly specify which columns to include, and in which order,
supply a "columns" array:
supply an "include" array:

@@ -174,3 +176,3 @@ ```js

var columns = columnify(data, {
columns: ['name', 'version'] // note description not included
include: ['name', 'version'] // note description not included
})

@@ -177,0 +179,0 @@

@@ -19,3 +19,3 @@ var test = require('tape')

var result = columnify(data, {
columns: ['name', 'version'],
include: ['name', 'version'],
})

@@ -22,0 +22,0 @@ t.ok(!(/description/gi.test(result)))

@@ -1,3 +0,4 @@

NAME DESCRIPTION VERSION
mod1 some description… 0.0.1
module-two another description… 0.2.0
NAME DESCRIPTION VERSION
mod1 some description 0.0.1
module-two another description… 0.2.0
module-three thisisaverylongword… 0.2.0

@@ -1,3 +0,4 @@

NAME DESCRIPTION VERSION
mod1 some description... 0.0.1
module-two another... 0.2.0
NAME DESCRIPTION VERSION
mod1 some description 0.0.1
module-two another... 0.2.0
module-three thisisaverylongwo... 0.2.0

@@ -8,3 +8,3 @@ var test = require('tape')

name: 'mod1',
description: 'some description which happens to be far larger than the max',
description: 'some description',
version: '0.0.1',

@@ -15,5 +15,9 @@ }, {

version: '0.2.0',
}, {
name: 'module-three',
description: 'thisisaverylongwordandshouldbetruncated',
version: '0.2.0',
}]
test('widths are limited when truncation enabled', function(t) {
test('columns are limited when truncation enabled', function(t) {
t.plan(1)

@@ -23,3 +27,3 @@ var expected = fs.readFileSync(__dirname + '/truncate-expected.txt', 'utf8')

truncate: true,
widths: {
config: {
description: {

@@ -26,0 +30,0 @@ maxWidth: 20

@@ -8,3 +8,3 @@ var test = require('tape')

name: 'mod1',
description: 'some description which happens to be far larger than the max',
description: 'some description',
version: '0.0.1',

@@ -15,2 +15,6 @@ }, {

version: '0.2.0',
}, {
name: 'module-three',
description: 'thisisaverylongwordandshouldbetruncated',
version: '0.2.0',
}]

@@ -21,6 +25,6 @@

var expected = fs.readFileSync(__dirname + '/truncate-expected.txt', 'utf8').replace(/…/g, '>')
t.equal(columnify(data, {
truncate: '>',
widths: {
truncateMarker: '>',
truncate: true,
config: {
description: {

@@ -36,6 +40,6 @@ maxWidth: 20

var expected = fs.readFileSync(__dirname + '/truncate-multichar-expected.txt', 'utf8')
t.equal(columnify(data, {
truncate: '...',
widths: {
truncateMarker: '...',
truncate: true,
config: {
description: {

@@ -42,0 +46,0 @@ maxWidth: 20

@@ -6,3 +6,4 @@ NAME DESCRIPTION VERSION

than the max
mod3 0.3.0
mod3 thisisaverylongwordandshouldb… 0.3.0
ewrapped
module-four-four-four-four 0.0.4

@@ -16,3 +16,3 @@ var test = require('tape')

name: 'mod3',
description: '',
description: 'thisisaverylongwordandshouldbewrapped',
version: '0.3.0',

@@ -29,3 +29,3 @@ }, {

t.equal(columnify(data, {
widths: {
config: {
description: {

@@ -32,0 +32,0 @@ maxWidth: 30,

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