// validation-type-stuff, missing params, // bad implications, custom checks. module.exports = function (yargs, usage) { var self = {} // validate appropriate # of non-option // arguments were provided, i.e., '_'. self.nonOptionCount = function (argv) { var demanded = yargs.getDemanded() if (demanded._ && argv._.length < demanded._.count) { if (demanded._.msg !== undefined) { usage.fail(demanded._.msg) } else { usage.fail('Not enough non-option arguments: got ' + argv._.length + ', need at least ' + demanded._.count ) } } } // make sure that any args that require an // value (--foo=bar), have a value. self.missingArgumentValue = function (argv) { var options = yargs.getOptions(), defaultValues = [true, false, ''] if (options.requiresArg.length > 0) { var missingRequiredArgs = [] options.requiresArg.forEach(function (key) { var value = argv[key] // if a value is explicitly requested, // flag argument as missing if it does not // look like foo=bar was entered. if (~defaultValues.indexOf(value) || (Array.isArray(value) && !value.length)) { missingRequiredArgs.push(key) } }) if (missingRequiredArgs.length === 1) { usage.fail('Missing argument value: ' + missingRequiredArgs[0]) } else if (missingRequiredArgs.length > 1) { var message = 'Missing argument values: ' + missingRequiredArgs.join(', ') usage.fail(message) } } } // make sure all the required arguments are present. self.requiredArguments = function (argv) { var demanded = yargs.getDemanded(), missing = null Object.keys(demanded).forEach(function (key) { if (!argv.hasOwnProperty(key)) { missing = missing || {} missing[key] = demanded[key] } }) if (missing) { var customMsgs = [] Object.keys(missing).forEach(function (key) { var msg = missing[key].msg if (msg && customMsgs.indexOf(msg) < 0) { customMsgs.push(msg) } }) var customMsg = customMsgs.length ? '\n' + customMsgs.join('\n') : '' usage.fail('Missing required arguments: ' + Object.keys(missing).join(', ') + customMsg) } } // check for unknown arguments (strict-mode). self.unknownArguments = function (argv, aliases) { var descriptions = usage.getDescriptions(), demanded = yargs.getDemanded(), unknown = [], aliasLookup = {} Object.keys(aliases).forEach(function (key) { aliases[key].forEach(function (alias) { aliasLookup[alias] = key }) }) Object.keys(argv).forEach(function (key) { if (key !== '$0' && key !== '_' && !descriptions.hasOwnProperty(key) && !demanded.hasOwnProperty(key) && !aliasLookup.hasOwnProperty(key)) { unknown.push(key) } }) if (unknown.length === 1) { usage.fail('Unknown argument: ' + unknown[0]) } else if (unknown.length > 1) { usage.fail('Unknown arguments: ' + unknown.join(', ')) } } // custom checks, added using the `check` option on yargs. var checks = [] self.check = function (f) { checks.push(f) } self.customChecks = function (argv, aliases) { checks.forEach(function (f) { try { var result = f(argv, aliases) if (!result) { usage.fail('Argument check failed: ' + f.toString()) } else if (typeof result === 'string') { usage.fail(result) } } catch (err) { usage.fail(err.message ? err.message : err) } }) } // check implications, argument foo implies => argument bar. var implied = {} self.implies = function (key, value) { if (typeof key === 'object') { Object.keys(key).forEach(function (k) { self.implies(k, key[k]) }) } else { implied[key] = value } } self.getImplied = function () { return implied } self.implications = function (argv) { var implyFail = [] Object.keys(implied).forEach(function (key) { var num, origKey = key, value = implied[key] // convert string '1' to number 1 num = Number(key) key = isNaN(num) ? key : num if (typeof key === 'number') { // check length of argv._ key = argv._.length >= key } else if (key.match(/^--no-.+/)) { // check if key doesn't exist key = key.match(/^--no-(.+)/)[1] key = !argv[key] } else { // check if key exists key = argv[key] } num = Number(value) value = isNaN(num) ? value : num if (typeof value === 'number') { value = argv._.length >= value } else if (value.match(/^--no-.+/)) { value = value.match(/^--no-(.+)/)[1] value = !argv[value] } else { value = argv[value] } if (key && !value) { implyFail.push(origKey) } }) if (implyFail.length) { var msg = 'Implications failed:\n' implyFail.forEach(function (key) { msg += (' ' + key + ' -> ' + implied[key]) }) usage.fail(msg) } } return self }