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

stdio

Package Overview
Dependencies
Maintainers
1
Versions
24
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

stdio - npm Package Compare versions

Comparing version 0.1.7 to 0.2.0

CHANGES.md

386

main.js

@@ -1,369 +0,23 @@

/*jslint node: true, nomen: true, vars: true, plusplus: true*/
'use strict';
/** _ _ _
* ___| |_ __| (_) ___
* / __| __/ _` | |/ _ \
* \__ \ || (_| | | (_) |
* |___/\__\__,_|_|\___/
*
* Standard input/output management for NodeJS
*
* Copyright (c) 2013- Sergio García <sgmonda@gmail.com>
* Distributed under MIT License
*
**/
// DEPENDENCIES
// Command-line arguments parsing
exports.getopt = require('./lib/getopt.js').getopt;
// GLOBALS
// Terminal questions/forms
exports.question = require('./lib/question.js').question;
var stdin = process.stdin;
var MAX_PROMPT_TRIES = 3;
// MAIN LOGIC
function preprocess (argv) {
var i, arg;
for (i = 0; i < argv.length; i++) {
arg = argv[i];
var parts = arg.match(/(.+[^\\])=(.+)/);
if (parts) {
argv.splice(i, 1, parts[1], parts[2]);
}
if(arg.match(/\\=/)){
argv.splice(i, 1, arg.replace(/\\=/g, '='));
}
}
return argv;
}
/**
* Parses command line options
* @param {function} options options specification
* @param {string} extra Extra arguments description
* @param {argv} arguments Arguments array (optionsl)
*/
module.exports.getopt = function (options, extra, argv) {
var opts = {}; // Options map
var arg; // Every argument
var expected;
var i;
var len;
var opt;
var optname;
var j;
var o;
var argvBackup;
argv = argv || process.argv;
argv = preprocess(argv);
argvBackup = argv.join('&%$·').split('&%$·');
// Arguments parsing
argv = argv.slice(2);
/**
* Creates the help description (to be used by printHelp(), for instance)
*/
opts.createHelp = function () {
var o = null, lines = [], maxLength, help = '';
for (o in options) {
if (options.hasOwnProperty(o)) {
var ops = ' ', i;
for (i = 0; i < options[o].args; i++) {
ops += '<ARG' + (i + 1) + '> ';
}
lines.push([' ' + (options[o].key ? '-' + options[o].key + ', --' : '--') + o + ops, (options[o].description || '') + (options[o].mandatory ? ' (mandatory)' : '') + (options[o].multiple ? ' (multiple)' : '')]);
}
}
maxLength = lines.reduce(function (prev, curr) {
var aux = curr[0].length;
if (aux > prev) {
return aux;
}
return prev;
}, 0);
lines.forEach(function (l) {
help += l[0] + (new Array(maxLength - l[0].length + 1)).join(' ') + '\t' + l[1] + '\n';
});
return help;
};
/**
* Prints the standard help message
*/
opts.printHelp = function () {
var usage = 'USAGE: ';
usage += 'node ' + argvBackup[1].split('/').pop() + ' [OPTIONS] ' + (extra || '');
usage += ', where OPTIONS are:';
console.log(usage);
process.stdout.write(opts.createHelp());
};
/**
* Perform the parsing
*/
for (i = 0, len = argv.length; i < len; i = i + 1) {
opt = null;
optname = null;
arg = argv[i];
if (arg.charAt(0) === '-') {
opt = {};
expected = null;
if (arg.charAt(1) === '-') {
// It's a long option
optname = arg.substring(2);
expected = options[optname];
if (!expected) {
console.log('Unknown option: --' + optname);
opts.printHelp();
process.exit(-1);
}
} else if (arg.charAt(1).match(/[a-zA-Z]/)) {
// It's a negative number, a short option (or many one)
var keys = arg.substring(1).split('');
keys.forEach(function (k) {
var name;
for (name in options) {
if (options[name].key === k) {
optname = name;
break;
}
}
expected = options[optname];
if (!expected) {
console.log('Unknown option: -' + k);
opts.printHelp();
process.exit(-1);
}
if (keys.length > 1) {
opts[optname] = true;
}
});
}
if (argv[i + 1]) {
// Arguments asociated with this option
if (expected.args === 1) {
i = i + 1;
opt = argv[i];
} else if (expected.args) {
opt = [];
for (j = i + 1; j < i + 1 + (expected.args || 0); j = j + 1) {
opt.push(argv[j]);
}
i += expected.args;
} else {
opt = true;
}
} else {
opt = true;
}
if (opt) {
if (expected.multiple && opts[optname]) {
if (Array.isArray(opts[optname])) {
opts[optname].push(opt);
} else {
opts[optname] = [opts[optname], opt];
}
} else {
opts[optname] = opt;
}
}
} else {
if (!opts.args) {
opts.args = [];
}
opts.args.push(argv[i]);
}
}
// Check if two options has the same short key
var key = null;
var shorts = {};
for (key in options) {
if (options.hasOwnProperty(key) && options[key].key) {
if (shorts[options[key].key]) {
console.log('Wrong options specification: There are two or more options with the key "-%s"', options[key].key);
process.exit(-1);
}
shorts[options[key].key] = true;
}
}
// Check if there is any mandatory and not specified option, or any wrong specified one
var mandatoryNotSpecified = [];
var wrongSpecified = [];
for (o in options) {
if (options.hasOwnProperty(o)) {
var argsCount = parseInt(options[o].args, 10);
if (opts[o] === true && argsCount === 1) {
// Wrong specified
wrongSpecified.push(o);
} else if (opts[o] && argsCount >= 2) {
for (i = 0; i < argsCount; i++) {
if (!opts[o][i]) {
// Wrong specified
wrongSpecified.push(o);
break;
}
}
} else if (!opts[o] && options[o].mandatory) {
// Not specified being mandatory
mandatoryNotSpecified.push(o);
}
}
}
if (wrongSpecified.length > 0) {
var error2 = 'Incomplete specification of option' + (mandatoryNotSpecified.length > 1 ? 's' : '') + ': ';
error2 += wrongSpecified.map(function (o) {
return '--' + o;
}).join(', ');
console.log(error2);
}
if (mandatoryNotSpecified.length > 0) {
var error = 'Mandatory option' + (mandatoryNotSpecified.length > 1 ? 's' : '') + ' not specified: ';
error += mandatoryNotSpecified.map(function (o) {
return '--' + o;
}).join(', ');
console.log(error);
}
if (mandatoryNotSpecified.length > 0 || wrongSpecified.length > 0) {
opts.printHelp();
process.exit(-1);
}
return opts;
};
/**
* Reads the complete standard input
* @param {function} callback
*/
module.exports.read = function (callback) {
if (!callback) {
throw new Error('no callback provided to readInput() call');
}
var inputdata;
stdin.resume();
var listener = function (text) {
inputdata += String(text);
};
stdin.on('data', listener);
stdin.on('end', function () {
stdin.removeListener('data', listener);
callback(inputdata);
});
};
/**
* Shows a prompt question with some possible answers
* @param {string} question Question to show
* @param {array} options Possible answers
* @param {function} callback Function to call with user response (err, response)
*/
module.exports.question = function (question, options, callback) {
// Options can be omited
if (typeof options === 'function' && !callback) {
callback = options;
options = null;
}
if (!question || (options && (!Array.isArray(options) || options.length < 2))) {
throw new Error('Stdio prompt question is malformed');
}
var tries = MAX_PROMPT_TRIES;
var performQuestion = function () {
var str = question;
if (options) {
str += ' [' + options.join('/') + ']';
}
str += ': ';
process.stdout.write(str);
};
stdin.resume();
var listener = function (data) {
var response = data.toString().toLowerCase().trim();
if (options && options.indexOf(response) === -1) {
console.log('Unexpected answer');
tries--;
if (tries === 0) {
stdin.removeListener('data', listener);
callback('Retries spent');
} else {
performQuestion();
}
return;
}
stdin.removeListener('data', listener);
callback(false, response);
};
stdin.addListener('data', listener);
performQuestion();
};
// Input reading
var reading = require('./lib/reading.js');
exports.read = reading.read;
exports.readByLines = reading.readByLines;
{
"name": "stdio",
"version": "0.1.7",
"description": "Module for standard input/output management with NodeJS",
"keywords": ["input", "console", "output", "terminal", "system"],
"homepage": "http://sgmonda.github.io/stdio/",
"version": "0.2.0",
"description": "Standard input/output management with NodeJS",
"keywords": ["input", "console", "output", "terminal", "system", "arguments", "cli"],
"homepage": "https://github.com/sgmonda/stdio",
"license": "MIT",

@@ -16,9 +16,15 @@ "main": "main.js",

},
"dependencies": {},
"devDependencies": {
"jasmine-node": "1.14.2",
"jshint": "2.5.1"
},
"engines": {
"node": "*"
},
"readmeFilename": "README.md",
"readmeFilename": "readme.md",
"scripts": {
"test": "node test/tests.js < test/lipsum.txt"
"jshint": "jshint main.js tests",
"test": "jasmine-node --matchall tests/"
}
}

@@ -1,7 +0,5 @@

Module for input/output management with nodejs.
Module for standard input/output management with nodejs.
[![Build Status](https://secure.travis-ci.org/sgmonda/stdio.png)](http://travis-ci.org/sgmonda/stdio)
Website: http://sgmonda.github.io/stdio/
[![NPM](https://nodei.co/npm/stdio.png)](https://nodei.co/npm/stdio/)

@@ -20,3 +18,4 @@

* Read standard input at once
* Make prompt questions
* Read standard input by lines
* Make command-line questions

@@ -58,8 +57,23 @@ ### 2.1. Parse Unix-like command line options

As you can see, every option in `ops` object can has 3 different type of values:
As you can see, every option in `ops` object can have one of the following 3 types of values:
* The boolean value `true` if it has been specified without an `args` attribute.
* A single `string` if it has been specified with `args: 1`.
* A `string` array, if it has been specified with `args` >= 2.
* A `string` array, if it has been specified with `args` > 1.
Options can have the `multiple` flag, in which case they can appear multiple times (with one argument each time). The value of that option will be an array with all provided arguments:
```
var ops = stdio.getopt({
'check': {key: 'c', description: 'What this option means', multiple: true}
});
```
```
node program.js -c 1 -c 2 -c 3
```
```
{ check: ['1', '2', '3'] }
```
Options can have the attribute `multiple`:

@@ -86,3 +100,3 @@

This module can generate an usage message automatically. You can use it when user specifies `--help` option, which is automatically supported. This code:
This module generates a descriptive usage message automatically. You'll see it when your program is called with `-- help` option (or its short version `-h`), which is automatically supported. The following code:

@@ -92,8 +106,8 @@ ```javascript

var ops = stdio.getopt({
una: {description: 'Sets something to some value', key: 'u', args: 2, mandatory: true},
var ops = exports.getopt({
una: {description: 'Sets something to some value', args: 2, mandatory: true},
otra_muy_larga: {description: 'A boolean flag', key: 'o', mandatory: true},
una_sin_desc: {description: 'Another boolean flag'},
ultima: {description: 'A description', key: 'u', args: 1}
}, '[FILE1] [FILE2] ...'); // Optional extra arguments description
});
```

@@ -104,41 +118,69 @@

```
USAGE: node something.js [OPTIONS] [FILE1] [FILE2] ...
-u, --una <ARG1> <ARG2> Sets something to some value (mandatory)
-o, --otra_muy_larga A boolean flag (mandatory)
--una_sin_desc Another boolean flag
-u, --ultima <ARG1> A description
USAGE: node main.js [OPTION1] [OPTION2]... arg1 arg2...
--una <ARG1> <ARG2> Sets something to some value (mandatory)
-o, --otra_muy_larga A boolean flag (mandatory)
--una_sin_desc Another boolean flag
-u, --ultima <ARG1> A description
```
If a non-expected option is given or a mandatory option is not, an error (followed by the usage message) will be shown, finishing your program automatically. It's cool, isn`t it?
If a non-expected option is given or a mandatory option isn't, then an error will be shown, suggesting to use `--help` option to know how to use your program and finishing it automatically.
```
Missing "una" argument.
Try "--help" for more information.
```
### 2.2. Read standard input at once
This simple following code will read the whole standard input.
The following code will read the whole standard input at once and put it into `text` variable.
```javascript
var stdio = require('stdio');
stdio.read(function(data){
console.log(data);
stdio.read(function(text){
console.log(text);
});
```
Obviously it is not recommended for huge input files.
Obviously it is recommended only for small input streams, for instance a small file:
### 2.3. Show prompt questions and wait user's answer
```
node myprogram.js < input-file.txt
```
### 2.3. Read standard input line by line
The following code will execute dynamically a function over every line, when it is read from the standard input:
```javascript
var stdio = require('stdio');
stdio.question('This is a question?', ['y', 'n'], function (err, answer) {
// Use answer here
stdio.readByLines(function lineHandler(line, index) {
// You can do whatever you want with every line
console.log('Line %d:', index, line);
}, function () {
console.log('Finished');
});
```
The previous code will show something like the following:
The previous code will apply `lineHandler()` to every line while they are read, without waiting the whole input to end, so it is very useful for large text streams. For instance a continuous log:
````
This is a question? [y/n]:
````
```
tail -f /var/log/system.log | node myprogram.js
```
and waits until user enters an answer. There will be 3 retries before reporting an error by mean of the callback.
### 2.4. Show prompt questions and wait user's answer
The following code will ask the user for some info and then print it.
```javascript
stdio.question('What is your name?', function (err, name) {
stdio.question('How old are you?', function (err, age) {
stdio.question('Are you male or female?', ['male', 'female'], function (err, sex) {
console.log('Your name is "%s". You are a "%s" "%s" years old.', name, sex, age);
});
});
});
```
By default `stdio.question()` offers some retries when allowed answers are restricted (see the male/female question above). If no possible answers are specified, then the user can answer whatever he wants to the question.
## 3. Testing

@@ -151,62 +193,1 @@

````
## Changelog
### 0.1.7
* Support for multiple options added by mean of `multiple: true` flag:
````
node test.js -c 1 -c 2 -c 3
````
### 0.1.6
* Arguments now can have "=" sign escaped: `node program.js -m loc.ark+\\=13960\\=t0000693r.meta.json` will give the following:
````
{
createHelp: [Function],
printHelp: [Function],
meta: 'loc.ark+=13960=t0000693r.meta.json'
}
````
### 0.1.5
* Added support for prompt questions without options
### 0.1.4
* New fancy feature! Now you can show simple prompts to interact with users by mean of a question.
* Old printf-like feature has been removed.
### 0.1.3
* Support for extended large options added. Now it is possible to write `--anoption=44` instead of `--anoption 44`. This works only for options with a single parameter.
### 0.1.2
* Bug fix: Negative numbers as parameters caused wrong errors.
### 0.1.1
* Grouped short options support added (for boolean flags). Now you can write `-abc` instead of `-a -b -c`.
* Usage message has been simplified. Extra arguments description is supported now.
### 0.1.0
* If an option is specified with less arguments than the specified, an error (and the help message) is shown and program finishes.
* Captured options now has 3 possible values: `true`, a single `string` or an array of `strings`. Much easier to use than in previous releases (but incompatible with them, so be careful updating).
## Projects using `stdio` module
The following projects are currently using `stdio` module:
* mammock: https://github.com/earmbrust/mammock
* sqsmonitor: https://github.com/hasallen/sqsmonitor
* frejus: https://npmjs.org/package/frejus
* cli-mirror: https://www.npmjs.org/package/cli_mirror
* parser-energymech: https://www.npmjs.org/package/parser-energymech
* tool-twist: https://www.npmjs.org/package/tooltwist
* vtools-cli: https://www.npmjs.org/package/vtools-cli
If you use this module in your project, please, let us know.

@@ -9,2 +9,3 @@ # TODO

- [ ] Create a stdio.inspect() function to inspect objects with color (maybe integrated with printf)
- [ ] Add support for dynamic arguments count for options: {..., args: '*'}

@@ -11,0 +12,0 @@ - [X] Add a function to print usage

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

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