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

cliui

Package Overview
Dependencies
Maintainers
1
Versions
25
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

cliui - npm Package Compare versions

Comparing version 5.0.0 to 6.0.0

19

CHANGELOG.md

@@ -5,5 +5,16 @@ # Change Log

# [5.0.0](https://github.com/yargs/cliui/compare/v4.1.0...v5.0.0) (2019-04-10)
## [6.0.0](https://www.github.com/yargs/cliui/compare/v5.0.0...v6.0.0) (2019-11-10)
### ⚠ BREAKING CHANGES
* update deps, drop Node 6
### Code Refactoring
* update deps, drop Node 6 ([62056df](https://www.github.com/yargs/cliui/commit/62056df))
## [5.0.0](https://github.com/yargs/cliui/compare/v4.1.0...v5.0.0) (2019-04-10)
### Bug Fixes

@@ -21,3 +32,3 @@

<a name="4.1.0"></a>
# [4.1.0](https://github.com/yargs/cliui/compare/v4.0.0...v4.1.0) (2018-04-23)
## [4.1.0](https://github.com/yargs/cliui/compare/v4.0.0...v4.1.0) (2018-04-23)

@@ -32,3 +43,3 @@

<a name="4.0.0"></a>
# [4.0.0](https://github.com/yargs/cliui/compare/v3.2.0...v4.0.0) (2017-12-18)
## [4.0.0](https://github.com/yargs/cliui/compare/v3.2.0...v4.0.0) (2017-12-18)

@@ -59,3 +70,3 @@

<a name="3.2.0"></a>
# [3.2.0](https://github.com/yargs/cliui/compare/v3.1.2...v3.2.0) (2016-04-11)
## [3.2.0](https://github.com/yargs/cliui/compare/v3.1.2...v3.2.0) (2016-04-11)

@@ -62,0 +73,0 @@

@@ -1,278 +0,305 @@

var stringWidth = require('string-width')
var stripAnsi = require('strip-ansi')
var wrap = require('wrap-ansi')
var align = {
'use strict'
const stringWidth = require('string-width')
const stripAnsi = require('strip-ansi')
const wrap = require('wrap-ansi')
const align = {
right: alignRight,
center: alignCenter
}
var top = 0
var right = 1
var bottom = 2
var left = 3
const top = 0
const right = 1
const bottom = 2
const left = 3
function UI (opts) {
this.width = opts.width
this.wrap = opts.wrap
this.rows = []
}
class UI {
constructor (opts) {
this.width = opts.width
this.wrap = opts.wrap
this.rows = []
}
UI.prototype.span = function () {
var cols = this.div.apply(this, arguments)
cols.span = true
}
span (...args) {
const cols = this.div(...args)
cols.span = true
}
UI.prototype.resetOutput = function () {
this.rows = []
}
UI.prototype.div = function () {
if (arguments.length === 0) this.div('')
if (this.wrap && this._shouldApplyLayoutDSL.apply(this, arguments)) {
return this._applyLayoutDSL(arguments[0])
resetOutput () {
this.rows = []
}
var cols = []
div (...args) {
if (args.length === 0) {
this.div('')
}
for (var i = 0, arg; (arg = arguments[i]) !== undefined; i++) {
if (typeof arg === 'string') cols.push(this._colFromString(arg))
else cols.push(arg)
}
if (this.wrap && this._shouldApplyLayoutDSL(...args)) {
return this._applyLayoutDSL(args[0])
}
this.rows.push(cols)
return cols
}
const cols = args.map(arg => {
if (typeof arg === 'string') {
return this._colFromString(arg)
}
UI.prototype._shouldApplyLayoutDSL = function () {
return arguments.length === 1 && typeof arguments[0] === 'string' &&
/[\t\n]/.test(arguments[0])
}
return arg
})
UI.prototype._applyLayoutDSL = function (str) {
var _this = this
var rows = str.split('\n')
var leftColumnWidth = 0
this.rows.push(cols)
return cols
}
// simple heuristic for layout, make sure the
// second column lines up along the left-hand.
// don't allow the first column to take up more
// than 50% of the screen.
rows.forEach(function (row) {
var columns = row.split('\t')
if (columns.length > 1 && stringWidth(columns[0]) > leftColumnWidth) {
leftColumnWidth = Math.min(
Math.floor(_this.width * 0.5),
stringWidth(columns[0])
)
}
})
_shouldApplyLayoutDSL (...args) {
return args.length === 1 && typeof args[0] === 'string' &&
/[\t\n]/.test(args[0])
}
// generate a table:
// replacing ' ' with padding calculations.
// using the algorithmically generated width.
rows.forEach(function (row) {
var columns = row.split('\t')
_this.div.apply(_this, columns.map(function (r, i) {
return {
text: r.trim(),
padding: _this._measurePadding(r),
width: (i === 0 && columns.length > 1) ? leftColumnWidth : undefined
_applyLayoutDSL (str) {
const rows = str.split('\n').map(row => row.split('\t'))
let leftColumnWidth = 0
// simple heuristic for layout, make sure the
// second column lines up along the left-hand.
// don't allow the first column to take up more
// than 50% of the screen.
rows.forEach(columns => {
if (columns.length > 1 && stringWidth(columns[0]) > leftColumnWidth) {
leftColumnWidth = Math.min(
Math.floor(this.width * 0.5),
stringWidth(columns[0])
)
}
}))
})
})
return this.rows[this.rows.length - 1]
}
// generate a table:
// replacing ' ' with padding calculations.
// using the algorithmically generated width.
rows.forEach(columns => {
this.div(...columns.map((r, i) => {
return {
text: r.trim(),
padding: this._measurePadding(r),
width: (i === 0 && columns.length > 1) ? leftColumnWidth : undefined
}
}))
})
UI.prototype._colFromString = function (str) {
return {
text: str,
padding: this._measurePadding(str)
return this.rows[this.rows.length - 1]
}
}
UI.prototype._measurePadding = function (str) {
// measure padding without ansi escape codes
var noAnsi = stripAnsi(str)
return [0, noAnsi.match(/\s*$/)[0].length, 0, noAnsi.match(/^\s*/)[0].length]
}
_colFromString (text) {
return {
text,
padding: this._measurePadding(text)
}
}
UI.prototype.toString = function () {
var _this = this
var lines = []
_measurePadding (str) {
// measure padding without ansi escape codes
const noAnsi = stripAnsi(str)
return [0, noAnsi.match(/\s*$/)[0].length, 0, noAnsi.match(/^\s*/)[0].length]
}
_this.rows.forEach(function (row, i) {
_this.rowToString(row, lines)
})
toString () {
const lines = []
// don't display any lines with the
// hidden flag set.
lines = lines.filter(function (line) {
return !line.hidden
})
this.rows.forEach(row => {
this.rowToString(row, lines)
})
return lines.map(function (line) {
return line.text
}).join('\n')
}
// don't display any lines with the
// hidden flag set.
return lines
.filter(line => !line.hidden)
.map(line => line.text)
.join('\n')
}
UI.prototype.rowToString = function (row, lines) {
var _this = this
var padding
var rrows = this._rasterize(row)
var str = ''
var ts
var width
var wrapWidth
rowToString (row, lines) {
this._rasterize(row).forEach((rrow, r) => {
let str = ''
rrow.forEach((col, c) => {
const { width } = row[c] // the width with padding.
const wrapWidth = this._negatePadding(row[c]) // the width without padding.
rrows.forEach(function (rrow, r) {
str = ''
rrow.forEach(function (col, c) {
ts = '' // temporary string used during alignment/padding.
width = row[c].width // the width with padding.
wrapWidth = _this._negatePadding(row[c]) // the width without padding.
let ts = col // temporary string used during alignment/padding.
ts += col
if (wrapWidth > stringWidth(col)) {
ts += ' '.repeat(wrapWidth - stringWidth(col))
}
for (var i = 0; i < wrapWidth - stringWidth(col); i++) {
ts += ' '
}
// align the string within its column.
if (row[c].align && row[c].align !== 'left' && this.wrap) {
ts = align[row[c].align](ts, wrapWidth)
if (stringWidth(ts) < wrapWidth) {
ts += ' '.repeat(width - stringWidth(ts) - 1)
}
}
// align the string within its column.
if (row[c].align && row[c].align !== 'left' && _this.wrap) {
ts = align[row[c].align](ts, wrapWidth)
if (stringWidth(ts) < wrapWidth) ts += new Array(width - stringWidth(ts)).join(' ')
}
// apply border and padding to string.
const padding = row[c].padding || [0, 0, 0, 0]
if (padding[left]) {
str += ' '.repeat(padding[left])
}
// apply border and padding to string.
padding = row[c].padding || [0, 0, 0, 0]
if (padding[left]) str += new Array(padding[left] + 1).join(' ')
str += addBorder(row[c], ts, '| ')
str += ts
str += addBorder(row[c], ts, ' |')
if (padding[right]) str += new Array(padding[right] + 1).join(' ')
str += addBorder(row[c], ts, '| ')
str += ts
str += addBorder(row[c], ts, ' |')
if (padding[right]) {
str += ' '.repeat(padding[right])
}
// if prior row is span, try to render the
// current row on the prior line.
if (r === 0 && lines.length > 0) {
str = _this._renderInline(str, lines[lines.length - 1])
}
})
// if prior row is span, try to render the
// current row on the prior line.
if (r === 0 && lines.length > 0) {
str = this._renderInline(str, lines[lines.length - 1])
}
})
// remove trailing whitespace.
lines.push({
text: str.replace(/ +$/, ''),
span: row.span
// remove trailing whitespace.
lines.push({
text: str.replace(/ +$/, ''),
span: row.span
})
})
})
return lines
}
function addBorder (col, ts, style) {
if (col.border) {
if (/[.']-+[.']/.test(ts)) return ''
else if (ts.trim().length) return style
else return ' '
return lines
}
return ''
}
// if the full 'source' can render in
// the target line, do so.
UI.prototype._renderInline = function (source, previousLine) {
var leadingWhitespace = source.match(/^ */)[0].length
var target = previousLine.text
var targetTextWidth = stringWidth(target.trimRight())
// if the full 'source' can render in
// the target line, do so.
_renderInline (source, previousLine) {
const leadingWhitespace = source.match(/^ */)[0].length
const target = previousLine.text
const targetTextWidth = stringWidth(target.trimRight())
if (!previousLine.span) return source
if (!previousLine.span) {
return source
}
// if we're not applying wrapping logic,
// just always append to the span.
if (!this.wrap) {
// if we're not applying wrapping logic,
// just always append to the span.
if (!this.wrap) {
previousLine.hidden = true
return target + source
}
if (leadingWhitespace < targetTextWidth) {
return source
}
previousLine.hidden = true
return target + source
return target.trimRight() + ' '.repeat(leadingWhitespace - targetTextWidth) + source.trimLeft()
}
if (leadingWhitespace < targetTextWidth) return source
_rasterize (row) {
const rrows = []
const widths = this._columnWidths(row)
let wrapped
previousLine.hidden = true
// word wrap all columns, and create
// a data-structure that is easy to rasterize.
row.forEach((col, c) => {
// leave room for left and right padding.
col.width = widths[c]
if (this.wrap) {
wrapped = wrap(col.text, this._negatePadding(col), { hard: true }).split('\n')
} else {
wrapped = col.text.split('\n')
}
return target.trimRight() + new Array(leadingWhitespace - targetTextWidth + 1).join(' ') + source.trimLeft()
}
if (col.border) {
wrapped.unshift('.' + '-'.repeat(this._negatePadding(col) + 2) + '.')
wrapped.push("'" + '-'.repeat(this._negatePadding(col) + 2) + "'")
}
UI.prototype._rasterize = function (row) {
var _this = this
var i
var rrow
var rrows = []
var widths = this._columnWidths(row)
var wrapped
// add top and bottom padding.
if (col.padding) {
wrapped.unshift(...new Array(col.padding[top] || 0).fill(''))
wrapped.push(...new Array(col.padding[bottom] || 0).fill(''))
}
// word wrap all columns, and create
// a data-structure that is easy to rasterize.
row.forEach(function (col, c) {
// leave room for left and right padding.
col.width = widths[c]
if (_this.wrap) wrapped = wrap(col.text, _this._negatePadding(col), { hard: true }).split('\n')
else wrapped = col.text.split('\n')
wrapped.forEach((str, r) => {
if (!rrows[r]) {
rrows.push([])
}
const rrow = rrows[r]
for (let i = 0; i < c; i++) {
if (rrow[i] === undefined) {
rrow.push('')
}
}
rrow.push(str)
})
})
return rrows
}
_negatePadding (col) {
let wrapWidth = col.width
if (col.padding) {
wrapWidth -= (col.padding[left] || 0) + (col.padding[right] || 0)
}
if (col.border) {
wrapped.unshift('.' + new Array(_this._negatePadding(col) + 3).join('-') + '.')
wrapped.push("'" + new Array(_this._negatePadding(col) + 3).join('-') + "'")
wrapWidth -= 4
}
// add top and bottom padding.
if (col.padding) {
for (i = 0; i < (col.padding[top] || 0); i++) wrapped.unshift('')
for (i = 0; i < (col.padding[bottom] || 0); i++) wrapped.push('')
return wrapWidth
}
_columnWidths (row) {
if (!this.wrap) {
return row.map(col => {
return col.width || stringWidth(col.text)
})
}
wrapped.forEach(function (str, r) {
if (!rrows[r]) rrows.push([])
let unset = row.length
let remainingWidth = this.width
rrow = rrows[r]
// column widths can be set in config.
const widths = row.map(col => {
if (col.width) {
unset--
remainingWidth -= col.width
return col.width
}
for (var i = 0; i < c; i++) {
if (rrow[i] === undefined) rrow.push('')
}
rrow.push(str)
return undefined
})
})
return rrows
}
// any unset widths should be calculated.
const unsetWidth = unset ? Math.floor(remainingWidth / unset) : 0
UI.prototype._negatePadding = function (col) {
var wrapWidth = col.width
if (col.padding) wrapWidth -= (col.padding[left] || 0) + (col.padding[right] || 0)
if (col.border) wrapWidth -= 4
return wrapWidth
return widths.map((w, i) => {
if (w === undefined) {
return Math.max(unsetWidth, _minWidth(row[i]))
}
return w
})
}
}
UI.prototype._columnWidths = function (row) {
var _this = this
var widths = []
var unset = row.length
var unsetWidth
var remainingWidth = this.width
function addBorder (col, ts, style) {
if (col.border) {
if (/[.']-+[.']/.test(ts)) {
return ''
}
// column widths can be set in config.
row.forEach(function (col, i) {
if (col.width) {
unset--
widths[i] = col.width
remainingWidth -= col.width
} else {
widths[i] = undefined
if (ts.trim().length !== 0) {
return style
}
})
// any unset widths should be calculated.
if (unset) unsetWidth = Math.floor(remainingWidth / unset)
widths.forEach(function (w, i) {
if (!_this.wrap) widths[i] = row[i].width || stringWidth(row[i].text)
else if (w === undefined) widths[i] = Math.max(unsetWidth, _minWidth(row[i]))
})
return ' '
}
return widths
return ''
}

@@ -283,5 +310,8 @@

function _minWidth (col) {
var padding = col.padding || []
var minWidth = 1 + (padding[left] || 0) + (padding[right] || 0)
if (col.border) minWidth += 4
const padding = col.padding || []
const minWidth = 1 + (padding[left] || 0) + (padding[right] || 0)
if (col.border) {
return minWidth + 4
}
return minWidth

@@ -291,3 +321,6 @@ }

function getWindowWidth () {
if (typeof process === 'object' && process.stdout && process.stdout.columns) return process.stdout.columns
/* istanbul ignore next: depends on terminal */
if (typeof process === 'object' && process.stdout && process.stdout.columns) {
return process.stdout.columns
}
}

@@ -297,10 +330,9 @@

str = str.trim()
var padding = ''
var strWidth = stringWidth(str)
const strWidth = stringWidth(str)
if (strWidth < width) {
padding = new Array(width - strWidth + 1).join(' ')
return ' '.repeat(width - strWidth) + str
}
return padding + str
return str
}

@@ -310,19 +342,17 @@

str = str.trim()
var padding = ''
var strWidth = stringWidth(str.trim())
const strWidth = stringWidth(str)
if (strWidth < width) {
padding = new Array(parseInt((width - strWidth) / 2, 10) + 1).join(' ')
/* istanbul ignore next */
if (strWidth >= width) {
return str
}
return padding + str
return ' '.repeat((width - strWidth) >> 1) + str
}
module.exports = function (opts) {
opts = opts || {}
module.exports = function (opts = {}) {
return new UI({
width: (opts || {}).width || getWindowWidth() || 80,
wrap: typeof opts.wrap === 'boolean' ? opts.wrap : true
width: opts.width || getWindowWidth() || /* istanbul ignore next */ 80,
wrap: opts.wrap !== false
})
}
{
"name": "cliui",
"version": "5.0.0",
"version": "6.0.0",
"description": "easily create complex multi-column command-line-interfaces",

@@ -9,4 +9,3 @@ "main": "index.js",

"test": "nyc mocha",
"coverage": "nyc --reporter=text-lcov mocha | coveralls",
"release": "standard-version"
"coverage": "nyc --reporter=text-lcov mocha | coveralls"
},

@@ -49,14 +48,13 @@ "repository": {

"dependencies": {
"string-width": "^3.1.0",
"strip-ansi": "^5.2.0",
"wrap-ansi": "^5.1.0"
"string-width": "^4.2.0",
"strip-ansi": "^6.0.0",
"wrap-ansi": "^6.2.0"
},
"devDependencies": {
"chai": "^4.2.0",
"chalk": "^2.4.2",
"chalk": "^3.0.0",
"coveralls": "^3.0.3",
"mocha": "^6.0.2",
"nyc": "^13.3.0",
"standard": "^12.0.1",
"standard-version": "^5.0.2"
"mocha": "^6.2.2",
"nyc": "^14.1.1",
"standard": "^12.0.1"
},

@@ -67,4 +65,4 @@ "files": [

"engine": {
"node": ">=6"
"node": ">=8"
}
}
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