Bug:Fix file validation issue
[vnfsdk/refrepo.git] / vnfmarket / src / main / webapp / vnfmarket / node_modules / cliui / index.js
1 var wrap = require('wordwrap'),
2   align = {
3     right: require('right-align'),
4     center: require('center-align')
5   },
6   top = 0,
7   right = 1,
8   bottom = 2,
9   left = 3
10
11 function UI (opts) {
12   this.width = opts.width
13   this.wrap = opts.wrap
14   this.rows = []
15 }
16
17 UI.prototype.span = function () {
18   var cols = this.div.apply(this, arguments)
19   cols.span = true
20 }
21
22 UI.prototype.div = function () {
23   if (arguments.length === 0) this.div('')
24   if (this.wrap && this._shouldApplyLayoutDSL.apply(this, arguments)) {
25     return this._applyLayoutDSL(arguments[0])
26   }
27
28   var cols = []
29
30   for (var i = 0, arg; (arg = arguments[i]) !== undefined; i++) {
31     if (typeof arg === 'string') cols.push(this._colFromString(arg))
32     else cols.push(arg)
33   }
34
35   this.rows.push(cols)
36   return cols
37 }
38
39 UI.prototype._shouldApplyLayoutDSL = function () {
40   return arguments.length === 1 && typeof arguments[0] === 'string' &&
41     /[\t\n]/.test(arguments[0])
42 }
43
44 UI.prototype._applyLayoutDSL = function (str) {
45   var _this = this,
46     rows = str.split('\n'),
47     leftColumnWidth = 0
48
49   // simple heuristic for layout, make sure the
50   // second column lines up along the left-hand.
51   // don't allow the first column to take up more
52   // than 50% of the screen.
53   rows.forEach(function (row) {
54     var columns = row.split('\t')
55     if (columns.length > 1 && columns[0].length > leftColumnWidth) {
56       leftColumnWidth = Math.min(
57         Math.floor(_this.width * 0.5),
58         columns[0].length
59       )
60     }
61   })
62
63   // generate a table:
64   //  replacing ' ' with padding calculations.
65   //  using the algorithmically generated width.
66   rows.forEach(function (row) {
67     var columns = row.split('\t')
68     _this.div.apply(_this, columns.map(function (r, i) {
69       return {
70         text: r.trim(),
71         padding: [0, r.match(/\s*$/)[0].length, 0, r.match(/^\s*/)[0].length],
72         width: (i === 0 && columns.length > 1) ? leftColumnWidth : undefined
73       }
74     }))
75   })
76
77   return this.rows[this.rows.length - 1]
78 }
79
80 UI.prototype._colFromString = function (str) {
81   return {
82     text: str
83   }
84 }
85
86 UI.prototype.toString = function () {
87   var _this = this,
88     lines = []
89
90   _this.rows.forEach(function (row, i) {
91     _this.rowToString(row, lines)
92   })
93
94   // don't display any lines with the
95   // hidden flag set.
96   lines = lines.filter(function (line) {
97     return !line.hidden
98   })
99
100   return lines.map(function (line) {
101     return line.text
102   }).join('\n')
103 }
104
105 UI.prototype.rowToString = function (row, lines) {
106   var _this = this,
107     paddingLeft,
108     rrows = this._rasterize(row),
109     str = '',
110     ts,
111     width,
112     wrapWidth
113
114   rrows.forEach(function (rrow, r) {
115     str = ''
116     rrow.forEach(function (col, c) {
117       ts = '' // temporary string used during alignment/padding.
118       width = row[c].width // the width with padding.
119       wrapWidth = _this._negatePadding(row[c]) // the width without padding.
120
121       for (var i = 0; i < Math.max(wrapWidth, col.length); i++) {
122         ts += col.charAt(i) || ' '
123       }
124
125       // align the string within its column.
126       if (row[c].align && row[c].align !== 'left' && _this.wrap) {
127         ts = align[row[c].align](ts.trim() + '\n' + new Array(wrapWidth + 1).join(' '))
128           .split('\n')[0]
129         if (ts.length < wrapWidth) ts += new Array(width - ts.length).join(' ')
130       }
131
132       // add left/right padding and print string.
133       paddingLeft = (row[c].padding || [0, 0, 0, 0])[left]
134       if (paddingLeft) str += new Array(row[c].padding[left] + 1).join(' ')
135       str += ts
136       if (row[c].padding && row[c].padding[right]) str += new Array(row[c].padding[right] + 1).join(' ')
137
138       // if prior row is span, try to render the
139       // current row on the prior line.
140       if (r === 0 && lines.length > 0) {
141         str = _this._renderInline(str, lines[lines.length - 1], paddingLeft)
142       }
143     })
144
145     // remove trailing whitespace.
146     lines.push({
147       text: str.replace(/ +$/, ''),
148       span: row.span
149     })
150   })
151
152   return lines
153 }
154
155 // if the full 'source' can render in
156 // the target line, do so.
157 UI.prototype._renderInline = function (source, previousLine, paddingLeft) {
158   var target = previousLine.text,
159     str = ''
160
161   if (!previousLine.span) return source
162
163   // if we're not applying wrapping logic,
164   // just always append to the span.
165   if (!this.wrap) {
166     previousLine.hidden = true
167     return target + source
168   }
169
170   for (var i = 0, tc, sc; i < Math.max(source.length, target.length); i++) {
171     tc = target.charAt(i) || ' '
172     sc = source.charAt(i) || ' '
173     // we tried to overwrite a character in the other string.
174     if (tc !== ' ' && sc !== ' ') return source
175     // there is not enough whitespace to maintain padding.
176     if (sc !== ' ' && i < paddingLeft + target.length) return source
177     // :thumbsup:
178     if (tc === ' ') str += sc
179     else str += tc
180   }
181
182   previousLine.hidden = true
183
184   return str
185 }
186
187 UI.prototype._rasterize = function (row) {
188   var _this = this,
189     i,
190     rrow,
191     rrows = [],
192     widths = this._columnWidths(row),
193     wrapped
194
195   // word wrap all columns, and create
196   // a data-structure that is easy to rasterize.
197   row.forEach(function (col, c) {
198     // leave room for left and right padding.
199     col.width = widths[c]
200     if (_this.wrap) wrapped = wrap.hard(_this._negatePadding(col))(col.text).split('\n')
201     else wrapped = col.text.split('\n')
202
203     // add top and bottom padding.
204     if (col.padding) {
205       for (i = 0; i < (col.padding[top] || 0); i++) wrapped.unshift('')
206       for (i = 0; i < (col.padding[bottom] || 0); i++) wrapped.push('')
207     }
208
209     wrapped.forEach(function (str, r) {
210       if (!rrows[r]) rrows.push([])
211
212       rrow = rrows[r]
213
214       for (var i = 0; i < c; i++) {
215         if (rrow[i] === undefined) rrow.push('')
216       }
217       rrow.push(str)
218     })
219   })
220
221   return rrows
222 }
223
224 UI.prototype._negatePadding = function (col) {
225   var wrapWidth = col.width
226   if (col.padding) wrapWidth -= (col.padding[left] || 0) + (col.padding[right] || 0)
227   return wrapWidth
228 }
229
230 UI.prototype._columnWidths = function (row) {
231   var _this = this,
232     widths = [],
233     unset = row.length,
234     unsetWidth,
235     remainingWidth = this.width
236
237   // column widths can be set in config.
238   row.forEach(function (col, i) {
239     if (col.width) {
240       unset--
241       widths[i] = col.width
242       remainingWidth -= col.width
243     } else {
244       widths[i] = undefined
245     }
246   })
247
248   // any unset widths should be calculated.
249   if (unset) unsetWidth = Math.floor(remainingWidth / unset)
250   widths.forEach(function (w, i) {
251     if (!_this.wrap) widths[i] = row[i].width || row[i].text.length
252     else if (w === undefined) widths[i] = Math.max(unsetWidth, _minWidth(row[i]))
253   })
254
255   return widths
256 }
257
258 // calculates the minimum width of
259 // a column, based on padding preferences.
260 function _minWidth (col) {
261   var padding = col.padding || []
262
263   return 1 + (padding[left] || 0) + (padding[right] || 0)
264 }
265
266 module.exports = function (opts) {
267   opts = opts || {}
268
269   return new UI({
270     width: (opts || {}).width || 80,
271     wrap: typeof opts.wrap === 'boolean' ? opts.wrap : true
272   })
273 }