diff --git a/fixture.js b/fixture.js index da358aa..7ceb8fe 100755 --- a/fixture.js +++ b/fixture.js @@ -16,3 +16,14 @@ var cli = meow({ Object.keys(cli.flags).forEach(function (el) { console.log(el); }); + +cli.stdinOrInput() + .then(function (input) { + input.forEach(function (element) { + console.log(element); + }); + }) + .catch(function (err) { + console.error(err.message); + process.exit(1); + }); diff --git a/index.js b/index.js index 54e6126..707db77 100644 --- a/index.js +++ b/index.js @@ -8,11 +8,15 @@ var redent = require('redent'); var readPkgUp = require('read-pkg-up'); var loudRejection = require('loud-rejection'); var normalizePackageData = require('normalize-package-data'); +var getStdin = require('get-stdin'); +var Promise = require('pinkie-promise'); // get the uncached parent delete require.cache[__filename]; var parentDir = path.dirname(module.parent.filename); +global.Promise = Promise; + module.exports = function (opts, minimistOpts) { loudRejection(); @@ -25,9 +29,20 @@ module.exports = function (opts, minimistOpts) { cwd: parentDir, normalize: false }).pkg, - argv: process.argv.slice(2) + argv: process.argv.slice(2), + inferType: false }, opts); + minimistOpts = objectAssign({string: ['_']}, minimistOpts); + + var index = minimistOpts.string.indexOf('_'); + + if (opts.inferType === false && index === -1) { + minimistOpts.string.push('_'); + } else if (opts.inferType === true && index !== -1) { + minimistOpts.string.splice(index, 1); + } + if (Array.isArray(opts.help)) { opts.help = opts.help.join('\n'); } @@ -69,6 +84,19 @@ module.exports = function (opts, minimistOpts) { flags: camelcaseKeys(argv), pkg: pkg, help: help, - showHelp: showHelp + showHelp: showHelp, + stdinOrInput: function () { + if (!_ && process.stdin.isTTY) { + return Promise.reject(new Error('input required')); + } + + if (_.length > 0) { + return Promise.resolve(_); + } + + return getStdin().then(function (data) { + return [data]; + }); + } }; }; diff --git a/package.json b/package.json index 9b28ffe..40054a8 100644 --- a/package.json +++ b/package.json @@ -39,16 +39,19 @@ ], "dependencies": { "camelcase-keys": "^2.0.0", + "get-stdin": "^5.0.1", "loud-rejection": "^1.0.0", "minimist": "^1.1.3", "normalize-package-data": "^2.3.4", "object-assign": "^4.0.1", + "pinkie-promise": "^2.0.0", "read-pkg-up": "^1.0.1", "redent": "^1.0.0", "trim-newlines": "^1.0.0" }, "devDependencies": { "ava": "*", + "execa": "^0.1.1", "indent-string": "^2.1.0", "xo": "*" } diff --git a/readme.md b/readme.md index 7ae8ab9..e3f0294 100644 --- a/readme.md +++ b/readme.md @@ -126,6 +126,15 @@ Default: `process.argv.slice(2)` Custom arguments object. +##### inferType + +Type: `boolean` +Default: `false` + +Infer the argument type. + +By default, the argument `5` in `$ foo 5` becomes a string. Enabling this would infer it as a number. + #### minimistOptions Type: `object` diff --git a/test.js b/test.js index f9f58d6..0274848 100644 --- a/test.js +++ b/test.js @@ -1,8 +1,11 @@ -import childProcess from 'child_process'; import test from 'ava'; import indentString from 'indent-string'; +import execa from 'execa'; +import pkg from './package.json'; import fn from './'; +global.Promise = Promise; + test('return object', t => { const cli = fn({ argv: ['foo', '--foo-bar', '-u', 'cat'], @@ -21,46 +24,29 @@ test('return object', t => { t.is(cli.flags.unicorn, 'cat'); t.is(cli.pkg.name, 'meow'); t.is(cli.help, indentString('\nCLI app helper\n\nUsage\n foo ', ' ')); - t.end(); }); test('support help shortcut', t => { const cli = fn(['unicorn', 'cat']); t.is(cli.help, indentString('\nCLI app helper\n\nunicorn\ncat', ' ')); - t.end(); }); -test('spawn cli and show version', t => { - t.plan(2); +test('spawn cli and show version', async t => { + const {stdout} = await execa('./fixture.js', ['--version']); - childProcess.execFile('./fixture.js', ['--version'], { - cwd: __dirname - }, (err, stdout) => { - t.ifError(err); - t.is(stdout.trim(), require('./package.json').version); - }); + t.is(stdout, pkg.version); }); -test('spawn cli and show help screen', t => { - t.plan(2); +test('spawn cli and show help screen', async t => { + const {stdout} = await execa('./fixture.js', ['--help']); - childProcess.execFile('./fixture.js', ['--help'], { - cwd: __dirname - }, (err, stdout) => { - t.ifError(err); - t.is(stdout, indentString('\nCustom description\n\nUsage\n foo \n', ' ')); - }); + t.is(stdout, indentString('\nCustom description\n\nUsage\n foo ', ' ')); }); -test('spawn cli and test input', t => { - t.plan(2); +test('spawn cli and test input', async t => { + const {stdout} = await execa('./fixture.js', ['foo', '-u', 'cat']); - childProcess.execFile('./fixture.js', ['-u', 'cat'], { - cwd: __dirname - }, (err, stdout) => { - t.ifError(err); - t.is(stdout, 'u\nunicorn\nmeow\n'); - }); + t.is(stdout, 'u\nunicorn\nmeow\nfoo'); }); test.serial('pkg.bin as a string should work', t => { @@ -72,10 +58,23 @@ test.serial('pkg.bin as a string should work', t => { }); t.is(process.title, 'browser-sync'); - t.end(); }); test('single character flag casing should be preserved', t => { t.ok(fn({argv: ['-F']}).flags.F); - t.end(); +}); + +test('type inference', t => { + t.is(fn({argv: ['5']}).input[0], '5'); + t.is(fn({argv: ['5']}, {string: ['_']}).input[0], '5'); + t.is(fn({argv: ['5'], inferType: true}).input[0], 5); + t.is(fn({argv: ['5'], inferType: true}, {string: ['foo']}).input[0], 5); +}); + +test('stdinOrInput', async t => { + const stdin = await execa.shell('echo \'foo bar\' | ./fixture.js'); + const input = await execa('./fixture.js', ['foo', 'bar']); + + t.is(stdin.stdout, 'meow\nfoo bar\n'); + t.is(input.stdout, 'meow\nfoo\nbar'); });