diff --git a/lib/argsert.js b/lib/argsert.js index c9a055a5d..d3e72fce5 100644 --- a/lib/argsert.js +++ b/lib/argsert.js @@ -1,54 +1,60 @@ const command = require('./command')() +const YError = require('./yerror') const positionName = ['first', 'second', 'third', 'fourth', 'fifth', 'sixth'] module.exports = function (expected, callerArguments, length) { - // preface the argument description with "cmd", so - // that we can run it through yargs' command parser. - var position = 0 - var parsed = {demanded: [], optional: []} - if (typeof expected === 'object') { - length = callerArguments - callerArguments = expected - } else { - parsed = command.parseCommand('cmd ' + expected) - } - const args = [].slice.call(callerArguments) + // TODO: should this eventually raise an exception. + try { + // preface the argument description with "cmd", so + // that we can run it through yargs' command parser. + var position = 0 + var parsed = {demanded: [], optional: []} + if (typeof expected === 'object') { + length = callerArguments + callerArguments = expected + } else { + parsed = command.parseCommand('cmd ' + expected) + } + const args = [].slice.call(callerArguments) - while (args.length && args[args.length - 1] === undefined) args.pop() - length = length || args.length + while (args.length && args[args.length - 1] === undefined) args.pop() + length = length || args.length - if (length < parsed.demanded.length) { - throw Error('Not enough arguments provided. Expected ' + parsed.demanded.length + - ' but received ' + args.length + '.') - } + if (length < parsed.demanded.length) { + throw new YError('Not enough arguments provided. Expected ' + parsed.demanded.length + + ' but received ' + args.length + '.') + } - const totalCommands = parsed.demanded.length + parsed.optional.length - if (length > totalCommands) { - throw Error('Too many arguments provided. Expected max ' + totalCommands + - ' but received ' + length + '.') - } + const totalCommands = parsed.demanded.length + parsed.optional.length + if (length > totalCommands) { + throw new YError('Too many arguments provided. Expected max ' + totalCommands + + ' but received ' + length + '.') + } - parsed.demanded.forEach(function (demanded) { - const arg = args.shift() - const observedType = guessType(arg) - const matchingTypes = demanded.cmd.filter(function (type) { - return type === observedType || type === '*' + parsed.demanded.forEach(function (demanded) { + const arg = args.shift() + const observedType = guessType(arg) + const matchingTypes = demanded.cmd.filter(function (type) { + return type === observedType || type === '*' + }) + if (matchingTypes.length === 0) argumentTypeError(observedType, demanded.cmd, position, false) + position += 1 }) - if (matchingTypes.length === 0) argumentTypeError(observedType, demanded.cmd, position, false) - position += 1 - }) - parsed.optional.forEach(function (optional) { - if (args.length === 0) return - const arg = args.shift() - const observedType = guessType(arg) - const matchingTypes = optional.cmd.filter(function (type) { - return type === observedType || type === '*' + parsed.optional.forEach(function (optional) { + if (args.length === 0) return + const arg = args.shift() + const observedType = guessType(arg) + const matchingTypes = optional.cmd.filter(function (type) { + return type === observedType || type === '*' + }) + if (matchingTypes.length === 0) argumentTypeError(observedType, optional.cmd, position, true) + position += 1 }) - if (matchingTypes.length === 0) argumentTypeError(observedType, optional.cmd, position, true) - position += 1 - }) + } catch (err) { + console.warn(err.stack) + } } function guessType (arg) { @@ -61,6 +67,6 @@ function guessType (arg) { } function argumentTypeError (observedType, allowedTypes, position, optional) { - throw Error('Invalid ' + (positionName[position] || 'manyith') + ' argument.' + + throw new YError('Invalid ' + (positionName[position] || 'manyith') + ' argument.' + ' Expected ' + allowedTypes.join(' or ') + ' but received ' + observedType + '.') } diff --git a/test/argsert.js b/test/argsert.js index 07262bc3b..9139d0d0e 100644 --- a/test/argsert.js +++ b/test/argsert.js @@ -1,98 +1,143 @@ /* global describe, it */ const argsert = require('../lib/argsert') -const expect = require('chai').expect +const checkOutput = require('./helpers/utils').checkOutput require('chai').should() describe('Argsert', function () { - it('does not throw exception if optional argument is not provided', function () { - argsert('[object]', [].slice.call(arguments)) + it('does not warn if optional argument is not provided', function () { + var o = checkOutput(function () { + argsert('[object]', [].slice.call(arguments)) + }) + + o.warnings.length.should.equal(0) }) - it('throws exception if wrong type is provided for optional argument', function () { - function foo (opts) { - argsert('[object|number]', [].slice.call(arguments)) - } - expect(function () { + it('warn if wrong type is provided for optional argument', function () { + var o = checkOutput(function () { + function foo (opts) { + argsert('[object|number]', [].slice.call(arguments)) + } + foo('hello') - }).to.throw(/Invalid first argument. Expected object or number but received string./) + }) + + o.warnings[0].should.match(/Invalid first argument. Expected object or number but received string./) }) - it('does not throw exception if optional argument is valid', function () { - function foo (opts) { - argsert('[object]', [].slice.call(arguments)) - } - foo({foo: 'bar'}) + it('does not warn if optional argument is valid', function () { + var o = checkOutput(function () { + function foo (opts) { + argsert('[object]', [].slice.call(arguments)) + } + + foo({foo: 'bar'}) + }) + + o.warnings.length.should.equal(0) }) - it('throws exception if required argument is not provided', function () { - expect(function () { + it('warns if required argument is not provided', function () { + var o = checkOutput(function () { argsert('', [].slice.call(arguments)) - }).to.throw(/Not enough arguments provided. Expected 1 but received 0./) + }) + + o.warnings[0].should.match(/Not enough arguments provided. Expected 1 but received 0./) }) - it('throws exception if required argument is of wrong type', function () { - function foo (opts) { - argsert('', [].slice.call(arguments)) - } - expect(function () { + it('warns if required argument is of wrong type', function () { + var o = checkOutput(function () { + function foo (opts) { + argsert('', [].slice.call(arguments)) + } + foo('bar') - }).to.throw(/Invalid first argument. Expected object but received string./) + }) + + o.warnings[0].should.match(/Invalid first argument. Expected object but received string./) }) it('supports a combination of required and optional arguments', function () { - function foo (opts) { - argsert(' [string|object]', [].slice.call(arguments)) - } - foo([], 'foo', {}) + var o = checkOutput(function () { + function foo (opts) { + argsert(' [string|object]', [].slice.call(arguments)) + } + + foo([], 'foo', {}) + }) + + o.warnings.length.should.equal(0) }) - it('throws an exception if too many arguments are provided', function () { - function foo (expected) { - argsert(' [batman]', [].slice.call(arguments)) - } - expect(function () { + it('warns if too many arguments are provided', function () { + var o = checkOutput(function () { + function foo (expected) { + argsert(' [batman]', [].slice.call(arguments)) + } + foo([], 33, 99) - }).to.throw(/Too many arguments provided. Expected max 2 but received 3./) + }) + + o.warnings[0].should.match(/Too many arguments provided. Expected max 2 but received 3./) }) it('configures function to accept 0 parameters, if only arguments object is provided', function () { - function foo (expected) { - argsert([].slice.call(arguments)) - } - expect(function () { + var o = checkOutput(function () { + function foo (expected) { + argsert([].slice.call(arguments)) + } + foo(99) - }).to.throw(/Too many arguments provided. Expected max 0 but received 1./) + }) + + o.warnings[0].should.match(/Too many arguments provided. Expected max 0 but received 1./) }) it('allows for any type if * is provided', function () { - function foo (opts) { - argsert('<*>', [].slice.call(arguments)) - } - foo('bar') + var o = checkOutput(function () { + function foo (opts) { + argsert('<*>', [].slice.call(arguments)) + } + + foo('bar') + }) + + o.warnings.length.should.equal(0) }) it('should ignore trailing undefined values', function () { - function foo (opts) { - argsert('<*>', [].slice.call(arguments)) - } - foo('bar', undefined, undefined) + var o = checkOutput(function () { + function foo (opts) { + argsert('<*>', [].slice.call(arguments)) + } + + foo('bar', undefined, undefined) + }) + + o.warnings.length.should.equal(0) }) it('should not ignore undefined values that are not trailing', function () { - function foo (opts) { - argsert('<*>', [].slice.call(arguments)) - } - expect(function () { + var o = checkOutput(function () { + function foo (opts) { + argsert('<*>', [].slice.call(arguments)) + } + foo('bar', undefined, undefined, 33) - }).to.throw(/Too many arguments provided. Expected max 1 but received 4./) + }) + + o.warnings[0].should.match(/Too many arguments provided. Expected max 1 but received 4./) }) it('supports null as special type', function () { - function foo (arg) { - argsert('', [].slice.call(arguments)) - } - foo(null) + var o = checkOutput(function () { + function foo (arg) { + argsert('', [].slice.call(arguments)) + } + foo(null) + }) + + o.warnings.length.should.equal(0) }) }) diff --git a/test/helpers/utils.js b/test/helpers/utils.js index d896dae67..5a2ccc4f9 100644 --- a/test/helpers/utils.js +++ b/test/helpers/utils.js @@ -10,6 +10,7 @@ exports.checkOutput = function (f, argv, cb) { var _argv = process.argv var _error = console.error var _log = console.log + var _warn = console.warn process.exit = function () { exit = true } process.env = Hash.merge(process.env, { _: 'node' }) @@ -17,9 +18,11 @@ exports.checkOutput = function (f, argv, cb) { var errors = [] var logs = [] + var warnings = [] console.error = function (msg) { errors.push(msg) } console.log = function (msg) { logs.push(msg) } + console.warn = function (msg) { warnings.push(msg) } var result @@ -57,6 +60,7 @@ exports.checkOutput = function (f, argv, cb) { console.error = _error console.log = _log + console.warn = _warn } function done () { @@ -65,6 +69,7 @@ exports.checkOutput = function (f, argv, cb) { return { errors: errors, logs: logs, + warnings: warnings, exit: exit, result: result }