source: trip-planner-front/node_modules/cliui/build/lib/index.js@ 59329aa

Last change on this file since 59329aa was 6a3a178, checked in by Ema <ema_spirova@…>, 3 years ago

initial commit

  • Property mode set to 100644
File size: 9.4 KB
Line 
1'use strict';
2const align = {
3 right: alignRight,
4 center: alignCenter
5};
6const top = 0;
7const right = 1;
8const bottom = 2;
9const left = 3;
10export class UI {
11 constructor(opts) {
12 var _a;
13 this.width = opts.width;
14 this.wrap = (_a = opts.wrap) !== null && _a !== void 0 ? _a : true;
15 this.rows = [];
16 }
17 span(...args) {
18 const cols = this.div(...args);
19 cols.span = true;
20 }
21 resetOutput() {
22 this.rows = [];
23 }
24 div(...args) {
25 if (args.length === 0) {
26 this.div('');
27 }
28 if (this.wrap && this.shouldApplyLayoutDSL(...args) && typeof args[0] === 'string') {
29 return this.applyLayoutDSL(args[0]);
30 }
31 const cols = args.map(arg => {
32 if (typeof arg === 'string') {
33 return this.colFromString(arg);
34 }
35 return arg;
36 });
37 this.rows.push(cols);
38 return cols;
39 }
40 shouldApplyLayoutDSL(...args) {
41 return args.length === 1 && typeof args[0] === 'string' &&
42 /[\t\n]/.test(args[0]);
43 }
44 applyLayoutDSL(str) {
45 const rows = str.split('\n').map(row => row.split('\t'));
46 let leftColumnWidth = 0;
47 // simple heuristic for layout, make sure the
48 // second column lines up along the left-hand.
49 // don't allow the first column to take up more
50 // than 50% of the screen.
51 rows.forEach(columns => {
52 if (columns.length > 1 && mixin.stringWidth(columns[0]) > leftColumnWidth) {
53 leftColumnWidth = Math.min(Math.floor(this.width * 0.5), mixin.stringWidth(columns[0]));
54 }
55 });
56 // generate a table:
57 // replacing ' ' with padding calculations.
58 // using the algorithmically generated width.
59 rows.forEach(columns => {
60 this.div(...columns.map((r, i) => {
61 return {
62 text: r.trim(),
63 padding: this.measurePadding(r),
64 width: (i === 0 && columns.length > 1) ? leftColumnWidth : undefined
65 };
66 }));
67 });
68 return this.rows[this.rows.length - 1];
69 }
70 colFromString(text) {
71 return {
72 text,
73 padding: this.measurePadding(text)
74 };
75 }
76 measurePadding(str) {
77 // measure padding without ansi escape codes
78 const noAnsi = mixin.stripAnsi(str);
79 return [0, noAnsi.match(/\s*$/)[0].length, 0, noAnsi.match(/^\s*/)[0].length];
80 }
81 toString() {
82 const lines = [];
83 this.rows.forEach(row => {
84 this.rowToString(row, lines);
85 });
86 // don't display any lines with the
87 // hidden flag set.
88 return lines
89 .filter(line => !line.hidden)
90 .map(line => line.text)
91 .join('\n');
92 }
93 rowToString(row, lines) {
94 this.rasterize(row).forEach((rrow, r) => {
95 let str = '';
96 rrow.forEach((col, c) => {
97 const { width } = row[c]; // the width with padding.
98 const wrapWidth = this.negatePadding(row[c]); // the width without padding.
99 let ts = col; // temporary string used during alignment/padding.
100 if (wrapWidth > mixin.stringWidth(col)) {
101 ts += ' '.repeat(wrapWidth - mixin.stringWidth(col));
102 }
103 // align the string within its column.
104 if (row[c].align && row[c].align !== 'left' && this.wrap) {
105 const fn = align[row[c].align];
106 ts = fn(ts, wrapWidth);
107 if (mixin.stringWidth(ts) < wrapWidth) {
108 ts += ' '.repeat((width || 0) - mixin.stringWidth(ts) - 1);
109 }
110 }
111 // apply border and padding to string.
112 const padding = row[c].padding || [0, 0, 0, 0];
113 if (padding[left]) {
114 str += ' '.repeat(padding[left]);
115 }
116 str += addBorder(row[c], ts, '| ');
117 str += ts;
118 str += addBorder(row[c], ts, ' |');
119 if (padding[right]) {
120 str += ' '.repeat(padding[right]);
121 }
122 // if prior row is span, try to render the
123 // current row on the prior line.
124 if (r === 0 && lines.length > 0) {
125 str = this.renderInline(str, lines[lines.length - 1]);
126 }
127 });
128 // remove trailing whitespace.
129 lines.push({
130 text: str.replace(/ +$/, ''),
131 span: row.span
132 });
133 });
134 return lines;
135 }
136 // if the full 'source' can render in
137 // the target line, do so.
138 renderInline(source, previousLine) {
139 const match = source.match(/^ */);
140 const leadingWhitespace = match ? match[0].length : 0;
141 const target = previousLine.text;
142 const targetTextWidth = mixin.stringWidth(target.trimRight());
143 if (!previousLine.span) {
144 return source;
145 }
146 // if we're not applying wrapping logic,
147 // just always append to the span.
148 if (!this.wrap) {
149 previousLine.hidden = true;
150 return target + source;
151 }
152 if (leadingWhitespace < targetTextWidth) {
153 return source;
154 }
155 previousLine.hidden = true;
156 return target.trimRight() + ' '.repeat(leadingWhitespace - targetTextWidth) + source.trimLeft();
157 }
158 rasterize(row) {
159 const rrows = [];
160 const widths = this.columnWidths(row);
161 let wrapped;
162 // word wrap all columns, and create
163 // a data-structure that is easy to rasterize.
164 row.forEach((col, c) => {
165 // leave room for left and right padding.
166 col.width = widths[c];
167 if (this.wrap) {
168 wrapped = mixin.wrap(col.text, this.negatePadding(col), { hard: true }).split('\n');
169 }
170 else {
171 wrapped = col.text.split('\n');
172 }
173 if (col.border) {
174 wrapped.unshift('.' + '-'.repeat(this.negatePadding(col) + 2) + '.');
175 wrapped.push("'" + '-'.repeat(this.negatePadding(col) + 2) + "'");
176 }
177 // add top and bottom padding.
178 if (col.padding) {
179 wrapped.unshift(...new Array(col.padding[top] || 0).fill(''));
180 wrapped.push(...new Array(col.padding[bottom] || 0).fill(''));
181 }
182 wrapped.forEach((str, r) => {
183 if (!rrows[r]) {
184 rrows.push([]);
185 }
186 const rrow = rrows[r];
187 for (let i = 0; i < c; i++) {
188 if (rrow[i] === undefined) {
189 rrow.push('');
190 }
191 }
192 rrow.push(str);
193 });
194 });
195 return rrows;
196 }
197 negatePadding(col) {
198 let wrapWidth = col.width || 0;
199 if (col.padding) {
200 wrapWidth -= (col.padding[left] || 0) + (col.padding[right] || 0);
201 }
202 if (col.border) {
203 wrapWidth -= 4;
204 }
205 return wrapWidth;
206 }
207 columnWidths(row) {
208 if (!this.wrap) {
209 return row.map(col => {
210 return col.width || mixin.stringWidth(col.text);
211 });
212 }
213 let unset = row.length;
214 let remainingWidth = this.width;
215 // column widths can be set in config.
216 const widths = row.map(col => {
217 if (col.width) {
218 unset--;
219 remainingWidth -= col.width;
220 return col.width;
221 }
222 return undefined;
223 });
224 // any unset widths should be calculated.
225 const unsetWidth = unset ? Math.floor(remainingWidth / unset) : 0;
226 return widths.map((w, i) => {
227 if (w === undefined) {
228 return Math.max(unsetWidth, _minWidth(row[i]));
229 }
230 return w;
231 });
232 }
233}
234function addBorder(col, ts, style) {
235 if (col.border) {
236 if (/[.']-+[.']/.test(ts)) {
237 return '';
238 }
239 if (ts.trim().length !== 0) {
240 return style;
241 }
242 return ' ';
243 }
244 return '';
245}
246// calculates the minimum width of
247// a column, based on padding preferences.
248function _minWidth(col) {
249 const padding = col.padding || [];
250 const minWidth = 1 + (padding[left] || 0) + (padding[right] || 0);
251 if (col.border) {
252 return minWidth + 4;
253 }
254 return minWidth;
255}
256function getWindowWidth() {
257 /* istanbul ignore next: depends on terminal */
258 if (typeof process === 'object' && process.stdout && process.stdout.columns) {
259 return process.stdout.columns;
260 }
261 return 80;
262}
263function alignRight(str, width) {
264 str = str.trim();
265 const strWidth = mixin.stringWidth(str);
266 if (strWidth < width) {
267 return ' '.repeat(width - strWidth) + str;
268 }
269 return str;
270}
271function alignCenter(str, width) {
272 str = str.trim();
273 const strWidth = mixin.stringWidth(str);
274 /* istanbul ignore next */
275 if (strWidth >= width) {
276 return str;
277 }
278 return ' '.repeat((width - strWidth) >> 1) + str;
279}
280let mixin;
281export function cliui(opts, _mixin) {
282 mixin = _mixin;
283 return new UI({
284 width: (opts === null || opts === void 0 ? void 0 : opts.width) || getWindowWidth(),
285 wrap: opts === null || opts === void 0 ? void 0 : opts.wrap
286 });
287}
Note: See TracBrowser for help on using the repository browser.