pixl-cli 1.0.16 → 1.0.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +42 -27
  2. package/cli.js +83 -0
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -43,14 +43,14 @@ This module provides utilities for creating command-line Node.js apps. Features
43
43
 
44
44
  Use [npm](https://www.npmjs.com/) to install the module:
45
45
 
46
- ```
46
+ ```sh
47
47
  npm install pixl-cli
48
48
  ```
49
49
 
50
50
  Then use `require()` to load it in your code:
51
51
 
52
- ```javascript
53
- var cli = require('pixl-cli');
52
+ ```js
53
+ const cli = require('pixl-cli');
54
54
  ```
55
55
 
56
56
  ## Basic Tools
@@ -62,7 +62,7 @@ Here are some of the more basic functions provided by the package.
62
62
  A very simple `cli.print()` method is provided, which prints any string to [STDOUT](https://nodejs.org/api/process.html#process_process_stdout). This can be shortened to just `print()` if you import everything into the global namespace (see [Importing Into Global](#importing-into-global) below). Example:
63
63
 
64
64
  ```js
65
- var cli = require('pixl-cli');
65
+ const cli = require('pixl-cli');
66
66
  cli.global();
67
67
 
68
68
  print("Hello world!\n");
@@ -75,7 +75,7 @@ Note that `print()` will be silent if `--quiet` mode is enabled. See [Quiet Mod
75
75
  An alternate function is provided for printing verbose output, called `cli.verbose()` (or just `verbose()` if [imported into global](#importing-into-global)). This function also prints a string to [STDOUT](https://nodejs.org/api/process.html#process_process_stdout), but only does so if `--verbose` mode is enabled. Example:
76
76
 
77
77
  ```js
78
- var cli = require('pixl-cli');
78
+ const cli = require('pixl-cli');
79
79
  cli.global();
80
80
 
81
81
  verbose("This will only be printed in verbose mode.\n");
@@ -88,7 +88,7 @@ See [Verbose Mode](#verbose-mode) below for details.
88
88
  To print something to [STDERR](https://nodejs.org/api/process.html#process_process_stderr) you can use the `cli.warn()` method. This works similarly as `cli.print()` in that it honors [Quiet Mode](#quiet-mode), does not include a trailing EOL, and gets imported to the global namespace if `cli.global()` is called. Example:
89
89
 
90
90
  ```js
91
- var cli = require('pixl-cli');
91
+ const cli = require('pixl-cli');
92
92
  cli.global();
93
93
 
94
94
  warn("This will be printed to STDERR.\n");
@@ -99,7 +99,7 @@ warn("This will be printed to STDERR.\n");
99
99
  To print something to [STDERR](https://nodejs.org/api/process.html#process_process_stderr) and exit immediately afterward, you can call `cli.die()` and pass in a message. This will exit with a non-zero code indicating that the process "failed". This method also gets imported to the global namespace if `cli.global()` is called. Example:
100
100
 
101
101
  ```js
102
- var cli = require('pixl-cli');
102
+ const cli = require('pixl-cli');
103
103
  cli.global();
104
104
 
105
105
  die("A fatal error occurred.\n");
@@ -110,7 +110,7 @@ die("A fatal error occurred.\n");
110
110
  To enable logging mode, so all calls to `print()`, `verbose()`, `warn()` and `die()` also get logged to a file, call `cli.setLogFile()` and pass in a path. The file need not exist, but the directory should. Example:
111
111
 
112
112
  ```js
113
- cli.setLogFile( "/var/log/myscript.log" );
113
+ cli.setLogFile( "/let/log/myscript.log" );
114
114
  ```
115
115
 
116
116
  Note that once the log file is set, everything printed is logged, even if quiet mode is enabled. Additionally, all calls to `cli.verbose()` are also logged, even if `--verbose` mode is not enabled.
@@ -129,9 +129,9 @@ You can also call `cli.log()` to log something directly without also printing it
129
129
  Simple methods are provided to load and save files to/from strings. These are both synchronous calls. They are `loadFile()` which accepts a file path and returns the contents as a string, and `saveFile()` which accepts a file path and contents as a string. `saveFile()` writes to the specified file, replacing any existing content, and creating the file if necessary. Example of both functions:
130
130
 
131
131
  ```js
132
- var cli = require('pixl-cli');
132
+ const cli = require('pixl-cli');
133
133
 
134
- var contents = cli.loadFile( "my-file.txt" );
134
+ let contents = cli.loadFile( "my-file.txt" );
135
135
  cli.print( "File contents: " + contents + "\n" );
136
136
 
137
137
  contents = "Replacing with new content!";
@@ -162,7 +162,7 @@ Specifically, this queries the [STDOUT](https://nodejs.org/api/process.html#proc
162
162
  To detect the width of the current TTY (user's terminal), you can call `cli.width()`. If a TTY is attached, this will return the current number of characters that will fit in one single line. Example:
163
163
 
164
164
  ```js
165
- var width = cli.width();
165
+ let width = cli.width();
166
166
  cli.print("Your terminal is " + width + " characters wide.\n");
167
167
  ```
168
168
 
@@ -188,13 +188,13 @@ In fact, the entire [pixl-tools](https://www.npmjs.com/package/pixl-tools) modul
188
188
 
189
189
  Any arguments passed to your script on the command-line are parsed using the [pixl-args](https://www.npmjs.com/package/pixl-args) module, and provided as simple key/value pairs in `cli.args`. Example:
190
190
 
191
- ```
191
+ ```sh
192
192
  node my-script.js --name "Joseph Huckaby" --city San\ Mateo
193
193
  ```
194
194
 
195
195
  Then `cli.args` will contain:
196
196
 
197
- ```js
197
+ ```json
198
198
  {
199
199
  "name": "Joseph Huckaby",
200
200
  "city": "San Mateo"
@@ -203,13 +203,13 @@ Then `cli.args` will contain:
203
203
 
204
204
  Several different kinds of arguments are available. You can use single or double-dashes, strings which appear to be integers or floats are parsed as such, any switch without a value is set to `true`, any repeated switches are converted to an array of values, and any values provided without a switch are appended to a special `other` array, which can come before or after all the switches. Here is an example of all these things:
205
205
 
206
- ```
206
+ ```sh
207
207
  node my-script.js file1.txt file2.txt --name "Joe" --amount 50 --freq 0.5 -z 1 --verbose --add thing1 --add thing2
208
208
  ```
209
209
 
210
210
  Then `cli.args` will contain:
211
211
 
212
- ```js
212
+ ```json
213
213
  {
214
214
  "other": ["file1.txt", "file2.txt"],
215
215
  "name": "Joe",
@@ -223,12 +223,25 @@ Then `cli.args` will contain:
223
223
 
224
224
  Please see the [pixl-args](https://www.npmjs.com/package/pixl-args) module documentation for more details.
225
225
 
226
+ ### Argument Aliases
227
+
228
+ You can support argument aliases (e.g. `-v` for `--verbose`) by providing a map to the `mapArgs()` function. Example:
229
+
230
+ ```js
231
+ const cli = require('pixl-cli');
232
+ cli.mapArgs({
233
+ 'v': 'verbose',
234
+ 'q': 'quiet',
235
+ 'd': 'debug'
236
+ });
237
+ ```
238
+
226
239
  ### Verbose Mode
227
240
 
228
241
  The `--verbose` switch has a special meaning. It is used by the `cli.verbose()` function, and will control whether it outputs anything or not. `cli.verbose()` works just like `cli.print()` except that it only prints if the `--verbose` switch is present on the command-line. Example use:
229
242
 
230
243
  ```js
231
- var cli = require('pixl-cli');
244
+ const cli = require('pixl-cli');
232
245
  cli.verbose("This will only be printed in verbose mode.\n");
233
246
  ```
234
247
 
@@ -241,7 +254,7 @@ The `--quiet` switch also has a special meaning. If passed on the command-line,
241
254
  To prompt the user for input, you can call `cli.prompt()`. Pass in a string to prompt them with, a default answer, and a callback function which will be fired and passed their answer. This is an asynchronous operation, so beware of code flow. Example:
242
255
 
243
256
  ```js
244
- var cli = require('pixl-cli');
257
+ const cli = require('pixl-cli');
245
258
 
246
259
  cli.prompt("What is your name?", "", function(name) {
247
260
  cli.print("Hello " + name + "!\n");
@@ -269,8 +282,8 @@ Note that if your script is running without a TTY (i.e. without an attached term
269
282
 
270
283
  Call `cli.box()` to render a string (or paragraph) of text surrounded by an ASCII art border. Example:
271
284
 
272
- ```
273
- var cli = require('pixl-cli');
285
+ ```js
286
+ const cli = require('pixl-cli');
274
287
 
275
288
  cli.print(
276
289
  cli.box("The quick brown fox jumped over the lazy dog.") + "\n"
@@ -298,7 +311,7 @@ Absent any options, the box will be sized to fit your text string, with exactly
298
311
  Example:
299
312
 
300
313
  ```js
301
- var text = "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.";
314
+ let text = "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.";
302
315
 
303
316
  cli.print(
304
317
  cli.box( text, {
@@ -390,9 +403,9 @@ id est laborum.
390
403
  Calling `cli.table()` produces a nicely formatted ASCII table with a grid of data. It expects an array of rows, and each element should be an array of columns. The first row will be rendered as the "header" and use a different style. Example:
391
404
 
392
405
  ```js
393
- var cli = require('pixl-cli');
406
+ const cli = require('pixl-cli');
394
407
 
395
- var rows = [
408
+ let rows = [
396
409
  [ "Username", "Full Name", "Email Address", "Status" ],
397
410
  [ "jhuckaby", "Joseph Huckaby", "jhuckaby@test.com", "Administrator" ],
398
411
  [ "tsmith", "Tom Smith", "smith@email.com", "Active" ],
@@ -424,6 +437,7 @@ Of course, if your Terminal supports ANSI color and font styles, the header woul
424
437
  | `textStyles` | An array of [chalk](https://www.npmjs.com/package/chalk) styles or functions to apply to the table cell text. |
425
438
  | `borderStyles` | An array of [chalk](https://www.npmjs.com/package/chalk) styles or functions to apply to the border graphics. |
426
439
  | `indent` | Number of characters to indent the table by (defaults to `0`). |
440
+ | `autoFit` | Automatically "fit" table into the available terminal width, if it is too wide. This will add ellipsis to longer columns as required. |
427
441
 
428
442
  Here is an example specifying all the possible options:
429
443
 
@@ -433,7 +447,8 @@ cli.print(
433
447
  headerStyles: ["bold", "yellow"],
434
448
  textStyles: ["cyan", function( text ) { return text.toUpperCase() }],
435
449
  borderStyles: ["gray"],
436
- indent: 0
450
+ indent: 0,
451
+ autoFit: true
437
452
  }) + "\n"
438
453
  );
439
454
  ```
@@ -451,9 +466,9 @@ To display a graphical ASCII progress bar, first call `cli.progress.start()` to
451
466
  Here is a simple example:
452
467
 
453
468
  ```js
454
- var cli = require('pixl-cli');
469
+ const cli = require('pixl-cli');
455
470
 
456
- var amount = 0;
471
+ let amount = 0;
457
472
  cli.progress.start();
458
473
 
459
474
  setInterval( function() {
@@ -631,7 +646,7 @@ cli.progress.start({
631
646
  All the style methods from the wonderful [chalk](https://www.npmjs.com/package/chalk) module are automatically imported, so you can use them like this:
632
647
 
633
648
  ```js
634
- var cli = require('pixl-cli');
649
+ const cli = require('pixl-cli');
635
650
  cli.print( cli.bold.red("This is bold and red!") + "\n" );
636
651
  ```
637
652
 
@@ -640,7 +655,7 @@ cli.print( cli.bold.red("This is bold and red!") + "\n" );
640
655
  You can optionally import some of the most commonly used methods into the global namespace, so you can use them from anywhere without having to prefix them. The method list includes `print()`, `verbose()`, a bunch of others (see below), as well as all the [chalk](https://www.npmjs.com/package/chalk) style methods. Example:
641
656
 
642
657
  ```js
643
- var cli = require('pixl-cli');
658
+ const cli = require('pixl-cli');
644
659
  cli.global();
645
660
 
646
661
  print( box( bold.red("This is bold, red and in a box!") ) + "\n" );
package/cli.js CHANGED
@@ -33,6 +33,17 @@ var cli = module.exports = {
33
33
  '(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-ntqry=><~]))'
34
34
  ].join('|'), 'g'),
35
35
 
36
+ mapArgs: function(aliases) {
37
+ // apply alias lookup to a set of args
38
+ // e.g. { 'q':'quiet', 'v':'verbose' }
39
+ for (var key in aliases) {
40
+ if (key in this.args) {
41
+ this.args[ aliases[key] ] = this.args[key];
42
+ delete this.args[key];
43
+ }
44
+ }
45
+ },
46
+
36
47
  tty: function() {
37
48
  // return true if stdout is connected to a TTY,
38
49
  // i.e. so we can ask the user things
@@ -234,6 +245,76 @@ var cli = module.exports = {
234
245
  return output.length ? output.join("\n") : "";
235
246
  },
236
247
 
248
+ autoFitTableRows: function(rows, args) {
249
+ // add ellipsis to rows as needed to fit entire table into horiz terminal width
250
+ var self = this;
251
+ var avail_width = (this.width() - (stringWidth(args.indent) * 2));
252
+ if (avail_width < 1) return;
253
+
254
+ var max_col_widths = [];
255
+ rows.forEach( function(cols, idx) {
256
+ cols.forEach( function(col, idy) {
257
+ max_col_widths[idy] = Math.max( max_col_widths[idy] || 0, stringWidth(''+col) );
258
+ } );
259
+ } );
260
+
261
+ var measureTableWidth = function() {
262
+ // measure table width with current settings and max_col_widths "virtually" applied
263
+ var widestCols = [];
264
+ rows.forEach( function(cols, idx) {
265
+ cols.forEach( function(col, idy) {
266
+ var sw = Math.min( stringWidth(''+col), max_col_widths[idy] );
267
+ widestCols[idy] = Math.max( widestCols[idy] || 0, sw + 2 );
268
+ } );
269
+ } );
270
+
271
+ var numCols = widestCols.length;
272
+ var line = "┌";
273
+ widestCols.forEach( function(num, idx) {
274
+ line += self.repeat("─", num);
275
+ if (idx < numCols - 1) line += "┬";
276
+ } );
277
+ line += "┐";
278
+
279
+ return line.length;
280
+ }; // measureTableWidth
281
+
282
+ // now keep chopping down max_col_widths until we fit
283
+ while (measureTableWidth() > avail_width) {
284
+ // find largest max_col_widths and decrement it by 1
285
+ var longest_col_width = Math.max.apply( Math, max_col_widths );
286
+ if (longest_col_width < 2) return; // e-brake
287
+
288
+ var longest_col_idx = max_col_widths.indexOf(longest_col_width);
289
+ if (longest_col_idx == -1) return; // sanity
290
+
291
+ max_col_widths[longest_col_idx]--;
292
+ }
293
+
294
+ // finally prune affected columns, trying to preserve ANSI color inside column value
295
+ rows.forEach( function(cols, idx) {
296
+ cols.forEach( function(col, idy) {
297
+ col = '' + col;
298
+ if (stringWidth(col) > max_col_widths[idy]) {
299
+ var suffix = '';
300
+ var prefix = '';
301
+
302
+ while (col.match(/^(\u001b\[[^m]*?m)/)) {
303
+ prefix += RegExp.$1;
304
+ col = col.replace(/^(\u001b\[[^m]*?m)/, '');
305
+ }
306
+
307
+ while (col.match(/(\u001b\[[^m]*?m)$/)) {
308
+ suffix = RegExp.$1 + suffix;
309
+ col = col.replace(/(\u001b\[[^m]*?m)$/, '');
310
+ }
311
+
312
+ cols[idy] = prefix + col.substring(0, max_col_widths[idy] - 1) + '…' + suffix;
313
+ } // too wide
314
+ });
315
+ });
316
+ },
317
+
237
318
  table: function(rows, args) {
238
319
  // render table of cols/rows with unicode borders
239
320
  // rows should be an array of arrays (columns), with row 0 being the header
@@ -247,6 +328,8 @@ var cli = module.exports = {
247
328
  args.indent = args.indent || "";
248
329
  if (typeof(args.indent) == 'number') args.indent = cli.space(args.indent);
249
330
 
331
+ if (args.autoFit) this.autoFitTableRows(rows, args);
332
+
250
333
  // calculate widest columns (+1spc of hpadding)
251
334
  var widestCols = [];
252
335
  rows.forEach( function(cols, idx) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pixl-cli",
3
- "version": "1.0.16",
3
+ "version": "1.0.18",
4
4
  "description": "Tools for building command-line apps for Node.js.",
5
5
  "author": "Joseph Huckaby <jhuckaby@gmail.com>",
6
6
  "homepage": "https://github.com/jhuckaby/pixl-cli",