Import Upstream version 1.14.1

parents
/tmp
/node_modules
/npm-debug.log
/.npmignore
/*.tgz
/tmp
/node_modules
/npm-debug.log
/tools
/test
/examples
/*.md
/*.txt
/AUTHORS
/Makefile
Trent Mick <trentm@gmail.com> (http://trentm.com)
Isaac Schlueter (https://github.com/isaacs)
Joshua M. Clulow (https://github.com/jclulow)
Patrick Mooney (https://github.com/pfmooney)
Dave Pacheco (https://github.com/davepacheco)
This diff is collapsed.
# This is the MIT license
Copyright (c) 2013 Trent Mick. All rights reserved.
Copyright (c) 2013 Joyent Inc. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
NODEUNIT = ./node_modules/.bin/nodeunit
JSSTYLE_FILES := $(shell find lib test -name "*.js")
NODEOPT ?= $(HOME)/opt
all $(NODEUNIT):
npm install
.PHONY: distclean
distclean:
rm -rf node_modules
.PHONY: test
test: | $(NODEUNIT)
$(NODEUNIT) test/*.test.js
.PHONY: testall
testall: test6 test7 test4 test012 test010
.PHONY: test6
test6:
@echo "# Test node 6.x (with node `$(NODEOPT)/node-6/bin/node --version`)"
@$(NODEOPT)/node-6/bin/node --version
PATH="$(NODEOPT)/node-6/bin:$(PATH)" make test
.PHONY: test7
test7:
@echo "# Test node 7.x (with node `$(NODEOPT)/node-7/bin/node --version`)"
@$(NODEOPT)/node-7/bin/node --version
PATH="$(NODEOPT)/node-7/bin:$(PATH)" make test
.PHONY: test4
test4:
@echo "# Test node 4.x (with node `$(NODEOPT)/node-4/bin/node --version`)"
@$(NODEOPT)/node-4/bin/node --version
PATH="$(NODEOPT)/node-4/bin:$(PATH)" make test
.PHONY: test012
test012:
@echo "# Test node 0.12.x (with node `$(NODEOPT)/node-0.12/bin/node --version`)"
@$(NODEOPT)/node-0.12/bin/node --version
PATH="$(NODEOPT)/node-0.12/bin:$(PATH)" make test
.PHONY: test010
test010:
@echo "# Test node 0.10.x (with node `$(NODEOPT)/node-0.10/bin/node --version`)"
@$(NODEOPT)/node-0.10/bin/node --version
PATH="$(NODEOPT)/node-0.10/bin:$(PATH)" make test
.PHONY: clean
clean:
rm -f dashdash-*.tgz
.PHONY: check-jsstyle
check-jsstyle: $(JSSTYLE_FILES)
./tools/jsstyle -o indent=4,doxygen,unparenthesized-return=0,blank-after-start-comment=0,leading-right-paren-ok $(JSSTYLE_FILES)
.PHONY: check
check:: check-jsstyle versioncheck
@echo "Check ok."
# Ensure CHANGES.md and package.json have the same version.
.PHONY: versioncheck
versioncheck:
@echo version is: $(shell cat package.json | json version)
[[ `cat package.json | json version` == `grep '^## ' CHANGES.md | head -2 | tail -1 | awk '{print $$2}'` ]]
.PHONY: cutarelease
cutarelease: versioncheck
[[ -z `git status --short` ]] # If this fails, the working dir is dirty.
@which json 2>/dev/null 1>/dev/null && \
ver=$(shell json -f package.json version) && \
name=$(shell json -f package.json name) && \
publishedVer=$(shell npm view -j $(shell json -f package.json name)@$(shell json -f package.json version) version 2>/dev/null) && \
if [[ -n "$$publishedVer" ]]; then \
echo "error: $$name@$$ver is already published to npm"; \
exit 1; \
fi && \
echo "** Are you sure you want to tag and publish $$name@$$ver to npm?" && \
echo "** Enter to continue, Ctrl+C to abort." && \
read
ver=$(shell cat package.json | json version) && \
date=$(shell date -u "+%Y-%m-%d") && \
git tag -a "$$ver" -m "version $$ver ($$date)" && \
git push --tags origin && \
npm publish
This diff is collapsed.
# someday/maybe
- being able to add types: i.e. a validator (easy to do, just haven't exposed)
- Maybe this later: var opts = parser.parse({argv: process.argv});
# notes: supporting opts from env or from a file
Say I have a 'foo' tool with a '-v' option for verbose. I also want
FOO_VERBOSE envvar to set verbose:
$ foo -v
debug: blah blah
...
$ FOO_VERBOSE=1 foo
debug: blah blah
...
foo.js:
var dashdash = require('dashdash')
var options = [{name: 'v', env: 'FOO_VERBOSE', type: 'bool'}];
var parser = new dashdash.Parser({options: options});
var opts = parser.parse(process.argv);
Say, also a ~/.foorc file is supported (somewhat a la ~/.ackrc) where
the file holds extra CLI opts:
$ cat ~/.foorc
-v -i
--file=foo.txt
Parsing that would look like:
var options = [
{name: 'v', env: 'FOO_VERBOSE', type: 'bool'},
{name: 'i', type: 'bool'},
{name: 'file', env: 'FOO_FILE', type: 'string'}
];
var parser = new dashdash.Parser({options: options});
var opts = parser.parse(process.argv);
This diff is collapsed.
#!/usr/bin/env node
/*
* Two custom option types that takes comma-separated values (excluding empty
* string values, trimming whitespace):
*
* - `commaSepString`: takes one option and returns an array of the values
* - `arrayOfCommaSepString`: accumulates comma-sep values from one or more
* uses of the option
*/
var path = require('path');
var format = require('util').format;
var dashdash = require('../lib/dashdash');
function parseCommaSepStringNoEmpties(option, optstr, arg) {
return arg.trim().split(/\s*,\s*/g)
.filter(function (part) { return part; });
}
dashdash.addOptionType({
name: 'commaSepString',
takesArg: true,
helpArg: 'STRING',
parseArg: parseCommaSepStringNoEmpties
});
dashdash.addOptionType({
name: 'arrayOfCommaSepString',
takesArg: true,
helpArg: 'STRING',
parseArg: parseCommaSepStringNoEmpties,
array: true,
arrayFlatten: true
});
var options = [
{ names: ['single', 's'], type: 'commaSepString' },
{ names: ['multi', 'm'], type: 'arrayOfCommaSepString' }
];
try {
var opts = dashdash.parse({options: options});
} catch (e) {
console.error('%s: error: %s', path.basename(process.argv[1]), e.message);
process.exit(1);
}
console.log('opts.single (-s): %j', opts.single);
console.log('opts.multi (-m): %j', opts.multi);
#!/usr/bin/env node
/*
* Example showing adding a custom option type to dashdash's parsing.
*
* Here we'll add a 'duration' option type. It supports durations specified
* like this:
* 1h meaning 1 hour
* 5m meaning 5 minutes
* 2d meaning 2 days
* 12s meaning 12 seconds
*
* For simplicity, our first cut doesn't support multiple scopes. E.g. we
* don't support "1h25m".
*
* The value of the parsed option is a number of milliseconds (that could
* then be added/subtracted from a current Date).
*/
var path = require('path');
var format = require('util').format;
var dashdash = require('../lib/dashdash');
var durationRe = /^([1-9]\d*)([smhd])$/;
function parseDuration(option, optstr, arg) {
var d;
var match = durationRe.exec(arg);
if (!match) {
throw new Error(format('arg for "%s" is not a valid duration: "%s"',
optstr, arg));
}
var num = match[1];
var scope = match[2];
var t = 0;
switch (scope) {
case 's':
t += num * 1000;
break;
case 'm':
t += num * 60 * 1000;
break;
case 'h':
t += num * 60 * 60 * 1000;
break;
case 'd':
t += num * 24 * 60 * 60 * 1000;
break;
}
return t;
}
// Here we add the new 'duration' option type to dashdash's set.
dashdash.addOptionType({
name: 'duration',
takesArg: true,
helpArg: 'DURATION',
parseArg: parseDuration
});
var options = [
{ names: ['time', 't'], type: 'duration' }
];
try {
var opts = dashdash.parse({options: options});
} catch (e) {
console.error('%s: error: %s', path.basename(process.argv[1]), e.message);
process.exit(1);
}
if (opts.time) {
console.log('duration: %d ms', opts.time);
}
#!/usr/bin/env node
/*
* Example showing adding a custom option type **with a default value**
* to dashdash's parsing.
*
*
* Here we'll add a 'fruit' option type, with 'apple' as the default.
*/
var path = require('path');
var format = require('util').format;
var dashdash = require('../lib/dashdash');
var fruits = [
'apple',
'pear',
'cherry',
'strawberry',
'banana'
];
function parseFruit(option, optstr, arg) {
if (fruits.indexOf(arg) === -1) {
throw new Error(format('arg for "%s" is not a known fruit: "%s"',
optstr, arg));
}
return arg;
}
// Here we add the new 'fruit' option type to dashdash's set.
dashdash.addOptionType({
name: 'fruit',
takesArg: true,
helpArg: 'FRUIT',
parseArg: parseFruit,
default: 'apple'
});
var options = [
{
names: ['help', 'h'], // first name is opts key
type: 'bool',
help: 'Print this help and exit.'
},
{ names: ['pie', 'p'], type: 'fruit', env: 'FRUIT' }
];
var parser = dashdash.createParser({options: options});
try {
var opts = parser.parse(process.argv);
} catch (e) {
console.error('%s: error: %s', path.basename(process.argv[1]), e.message);
process.exit(1);
}
if (opts.help) {
var help = parser.help({
includeEnv: true,
includeDefault: true
}).trimRight();
console.log('usage: node custom-option-fruit.js [OPTIONS]\n'
+ 'options:\n'
+ help);
process.exit(0);
}
console.log('pie fruit: %s', opts.pie);
#!/usr/bin/env node
/*
* As of version 1.13.0, dashdash changed the meaning of 'positiveInteger'
* to NOT accept zero. This example shows how to add a custom option type
* that supports the old behaviour, if needed.
*/
var path = require('path');
var format = require('util').format;
var dashdash = require('../lib/dashdash');
function parseIntGteZero(option, optstr, arg) {
var num = Number(arg);
if (!/^[0-9]+$/.test(arg) || isNaN(num)) {
throw new Error(format('arg for "%s" is not an integer >=0: "%s"',
optstr, arg));
}
return num;
}
dashdash.addOptionType({
name: 'intGteZero',
takesArg: true,
helpArg: 'INT',
parseArg: parseIntGteZero
});
// --- example parsing using intGteZero type
var options = [
{ names: ['num', 'n'], type: 'intGteZero' }
];
try {
var opts = dashdash.parse({options: options});
} catch (e) {
console.error('%s: error: %s', path.basename(process.argv[1]), e.message);
process.exit(1);
}
if (opts.num) {
console.log('num: %d', opts.num);
}
#!/usr/bin/env node
/*
* Example showing adding a custom option type to dashdash's parsing.
* Here we'll add a 'timeAgo' option type. See the comment below.
*/
var path = require('path');
var format = require('util').format;
var dashdash = require('../lib/dashdash');
/**
* A 'time' option type that allows either a duration (an amount of time ago):
* 1h one hour ago
* 2d two days ago
* 90m ninety minutes ago
* 120s 120 seconds ago
* or a date (another parsable by `new Date()`).
*/
var durationRe = /^([1-9]\d*)([smhd])$/;
function parseTimeAgo(option, optstr, arg) {
var t;
var match = durationRe.exec(arg);
if (match) {
var num = match[1];
var scope = match[2];
var delta = 0;
switch (scope) {
case 's':
delta += num * 1000;
break;
case 'm':
delta += num * 60 * 1000;
break;
case 'h':
delta += num * 60 * 60 * 1000;
break;
case 'd':
delta += num * 24 * 60 * 60 * 1000;
break;
}
t = new Date(Date.now() - delta);
} else {
try {
t = dashdash.parseDate(arg);
} catch (ex) {
throw new Error(format('arg for "%s" is not a valid duration ' +
'(e.g. 1h) or date: "%s"', optstr, arg));
}
}
return t;
}
// Here we add the new 'duration' option type to dashdash's set.
dashdash.addOptionType({
name: 'timeAgo',
takesArg: true,
helpArg: 'TIME',
parseArg: parseTimeAgo
});
// ---- example usage
var options = [
{ names: ['time', 't'], type: 'timeAgo' }
];
try {
var opts = dashdash.parse({options: options});
} catch (e) {
console.error('%s: error: %s', path.basename(process.argv[1]), e.message);
process.exit(1);
}
if (opts.time) {
console.log('time (ISO format): %s', opts.time.toISOString());
}
#!/usr/bin/env node
/*
* Small example showing dashdash's "date" option type.
*/
var dashdash = require('../lib/dashdash');
var options = [
{ names: ['start', 's'], type: 'date' },
{ names: ['end', 'e'], type: 'date' }
];
try {
var opts = dashdash.parse({options: options});
} catch (e) {
console.error('date.js: error: %s', e.message);
process.exit(1);
}
if (opts.start) {
console.log('start at', opts.start.toISOString());
}
if (opts.end) {
console.log('end at', opts.end.toISOString());
}
#!/usr/bin/env node
/*
* An example tool that shows how to get Bash completion using dashdash's
* helpers for this.
*
* Usage:
* # One time setup:
* cd examples/
* alias ddcompletion='node ddcompletion.js'
* ddcompletion --completion > /usr/local/etc/bash_completion.d/ddcompletion
* source /usr/local/etc/bash_completion.d/ddcompletion
*
* # Now play with the bash completion:
* ddcompletion -<TAB> # complete options
* ddcompletion --none <TAB> # explicit "no completions"
* ddcompletion -H <TAB> # complete custom "knownhosts" type
* ddcompletion <TAB> # complete first positional arg type
* ddcompletion banana <TAB> # complete second position arg type
*/
var dashdash = require('../lib/dashdash');
var options = [
{ name: 'version', type: 'bool', help: 'Print tool version and exit.' },
{ names: ['help', 'h'], type: 'bool', help: 'Print this help and exit.' },
{ names: ['verbose', 'v'], type: 'arrayOfBool', help: 'Verbose output.' },
{ names: ['file', 'f'], type: 'string', helpArg: 'FILE' },
// Add a (hidden) '--completion' that will emit the bash completion content.
{
names: ['completion'],
type: 'bool',
hidden: true
},
{
names: ['host', 'H'],
type: 'string',
// We'll define a custom completion type and, further down, a Bash
// completion function for this type. Test it with:
// $ ddcompletion --host <TAB>
completionType: 'knownhosts',
help: 'A known host (taken from ~/.ssh/known_hosts).'
},
{
names: ['none', 'N'],
type: 'string',
// Show off the 'none' completion type, which uses somewhat of
// a hack to enforce no completions on <TAB>.
completionType: 'none',
help: 'Testing "none" argtype. Should be no completions on <TAB>.'
}
];
var completionFuncs = [
// A 'knownhosts' completer function.
'function complete_knownhosts {',
' local word="$1"',
' local candidates',
' candidates=$(cat ~/.ssh/known_hosts | awk \'{print $1}\' | grep \'^[a-zA-Z]\' | cut -d, -f1)',
' compgen $compgen_opts -W "$candidates" -- "$word"',
'}',
// A 'fruit' completer function for the first positional arg.
'function complete_fruit {',
' compgen $compgen_opts -W "apple banana orange" -- "$1"',
'}'
].join('\n');
var parser = dashdash.createParser({options: options});
try {
var opts = parser.parse(process.argv);
} catch (e) {
console.error('foo: error: %s', e.message);
process.exit(1);
}
if (opts.help) {
var help = parser.help({includeEnv: true}).trimRight();
console.log('usage: node ddcompletion.js [OPTIONS]\n'
+ 'options:\n'
+ help);
process.exit(0);
} else if (opts.completion) {
// Use the `parser.bashCompletion()` helper to create the Bash
// completion file content, then just dump it.
console.log( parser.bashCompletion({
name: 'ddcompletion',
specExtra: completionFuncs,
// Define the first positional arg to be a fruit, and subsequent
// args to be 'file'.
argtypes: ['fruit', 'file']
}) );
process.exit(0);
}
// ...
console.log('opts:', opts);
console.log('args:', opts._args);
console.log('...')
#!/usr/bin/env node
/*
* An example using a sampling of dashdash's features. See "hello.js" and
* "help.js" for smaller examples.
*/
var dashdash = require('../lib/dashdash');
// Specify the options. Minimally `name` (or `names`) and `type`
// must be given for each.
var options = [
{
name: 'version', // `name` or `names`
type: 'bool',
help: 'Print tool version and exit.'
},
{
names: ['help', 'h'], // first name is opts key
type: 'bool',
help: 'Print this help and exit.'
},
{
names: ['verbose', 'v'],
type: 'arrayOfBool',
env: 'FOO_VERBOSE',
help: 'Verbose output. Use multiple times for more verbose.'
},
{
names: ['b'],
type: 'bool',
help: 'A boolean arg',
},
{
names: ['file', 'f'],
type: 'string',
env: 'FOO_FILE',
help: 'File to process',
helpArg: 'FILE'
},
{
names: ['timeout', 't'],
type: 'positiveInteger',
env: 'FOO_TIMEOUT',
help: 'Processing timeout in milliseconds',
helpArg: 'MS'
}
];
var parser = dashdash.createParser({options: options});
try {
var opts = parser.parse(process.argv);
} catch (e) {
console.error('foo: error: %s', e.message);
process.exit(1);
}
// Or a shortcut:
// var opts = dashdash.parse({options: options});
console.log("# opts:", opts);
console.log("# args:", opts._args);
// Use `parser.help()` for formatted options help.
if (opts.help) {
var help = parser.help({includeEnv: true}).trimRight();
console.log('usage: node foo.js [OPTIONS]\n'
+ 'options:\n'
+ help);
process.exit(0);
}
// ...
#!/usr/bin/env node
/*
* The smallest example using dashdash for option processing.
*/
var dashdash = require('../lib/dashdash');
// Define your options.
var options = [
{
names: ['verbose', 'v'], // first name is opts key
type: 'bool',
help: 'More verbose output.'
}
];
// Shortcut to create parser and parse `process.argv` in one step.
try {
var opts = dashdash.parse({options: options});
} catch (e) {
console.error('hello: error: %s', e.message);
process.exit(1);
}
if (opts.verbose) {
console.log("# opts:", opts);