diff --git a/lib/dashdash.js b/lib/dashdash.js index adb6f13..1368a9c 100644 --- a/lib/dashdash.js +++ b/lib/dashdash.js @@ -103,7 +103,33 @@ function optionKeyFromName(name) { return name.replace(/-/g, '_'); } - +// ---- Error types +var error_names = [ + "NOT_A_NUMBER", + "NOT_AN_INTEGER", + "NOT_A_POSITIVE_INTEGER", + "NOT_A_DATE_FORMAT", + "INVALID_DATE", + "UNKNOWN_OPTION", + "UNKNOWN_OPTION_IN_GROUP", + "ARG_TO_OPTION_NOT_ALLOWED", + "ARG_TO_OPTION_MISSING" +] + +var ERRORS = {}; +error_names.forEach(function(n) { + ERRORS[n] = n; +}) + +function augment_error(err, type, data) { + err.type = type; + if (data) { + Object.keys(data).forEach(function (k) { + err[k] = data[k]; + }) + } + return err; +} // ---- Option types @@ -120,8 +146,12 @@ function parseNumber(option, optstr, arg) { assert.string(arg, 'arg'); var num = Number(arg); if (isNaN(num)) { - throw new Error(format('arg for "%s" is not a number: "%s"', - optstr, arg)); + throw augment_error( + new Error(format('arg for "%s" is not a number: "%s"', + optstr, arg)), + ERRORS.NOT_A_NUMBER, + {optstr: optstr, arg: arg} + ) } return num; } @@ -130,8 +160,12 @@ function parseInteger(option, optstr, arg) { assert.string(arg, 'arg'); var num = Number(arg); if (!/^[0-9-]+$/.test(arg) || isNaN(num)) { - throw new Error(format('arg for "%s" is not an integer: "%s"', - optstr, arg)); + throw augment_error( + new Error(format('arg for "%s" is not an integer: "%s"', + optstr, arg)), + ERRORS.NOT_AN_INTEGER, + {optstr: optstr, arg: arg} + ) } return num; } @@ -140,8 +174,12 @@ function parsePositiveInteger(option, optstr, arg) { assert.string(arg, 'arg'); var num = Number(arg); if (!/^[0-9]+$/.test(arg) || isNaN(num) || num === 0) { - throw new Error(format('arg for "%s" is not a positive integer: "%s"', - optstr, arg)); + throw augment_error( + new Error(format('arg for "%s" is not a positive integer: "%s"', + optstr, arg)), + ERRORS.NOT_A_POSITIVE_INTEGER, + {optstr: optstr, arg: arg} + ) } return num; } @@ -167,12 +205,20 @@ function parseDate(option, optstr, arg) { // ISO 8601 format date = new Date(arg); } else { - throw new Error(format('arg for "%s" is not a valid date format: "%s"', - optstr, arg)); + throw augment_error( + new Error(format('arg for "%s" is not a valid date format: "%s"', + optstr, arg)), + ERRORS.NOT_A_DATE_FORMAT, + {optstr: optstr, arg: arg} + ) } if (date.toString() === 'Invalid Date') { - throw new Error(format('arg for "%s" is an invalid date: "%s"', - optstr, arg)); + throw augment_error( + new Error(format('arg for "%s" is an invalid date: "%s"', + optstr, arg)), + ERRORS.INVALID_DATE, + {optstr: optstr, arg: arg} + ) } return date; } @@ -417,7 +463,11 @@ Parser.prototype.parse = function parse(inputs) { var option = this.optionFromName[name]; if (!option) { if (!this.allowUnknown) - throw new Error(format('unknown option: "--%s"', name)); + throw augment_error( + new Error(format('unknown option: "--%s"', name)), + ERRORS.UNKNOWN_OPTION, + {optstr: format("--%s", name)} + ) else if (this.interspersed) _args.push(arg); else @@ -425,16 +475,24 @@ Parser.prototype.parse = function parse(inputs) { } else { var takesArg = this.optionTakesArg(option); if (val !== null && !takesArg) { - throw new Error(format('argument given to "--%s" option ' - + 'that does not take one: "%s"', name, arg)); + throw augment_error( + new Error(format('argument given to "--%s" option ' + + 'that does not take one: "%s"', name, arg)), + ERRORS.ARG_TO_OPTION_NOT_ALLOWED, + {optstr: format("--%s", name), arg: arg} + ) } if (!takesArg) { addOpt(option, '--'+name, option.key, true, 'argv'); } else if (val !== null) { addOpt(option, '--'+name, option.key, val, 'argv'); } else if (i + 1 >= args.length) { - throw new Error(format('do not have enough args for "--%s" ' - + 'option', name)); + throw augment_error( + new Error(format('do not have enough args for "--%s" ' + + 'option', name)), + ERRORS.ARG_TO_OPTION_MISSING, + {optstr: format("--%s", name)} + ) } else { addOpt(option, '--'+name, option.key, args[i + 1], 'argv'); i++; @@ -457,11 +515,19 @@ Parser.prototype.parse = function parse(inputs) { } else break outer; } else if (arg.length > 2) { - throw new Error(format( - 'unknown option: "-%s" in "%s" group', - name, arg)); + throw augment_error( + new Error(format( + 'unknown option: "-%s" in "%s" group', + name, arg)), + ERRORS.UNKNOWN_OPTION_IN_GROUP, + {optstr: format("-%s", name), group: arg} + ) } else { - throw new Error(format('unknown option: "-%s"', name)); + throw augment_error( + new Error(format('unknown option: "-%s"', name)), + ERRORS.UNKNOWN_OPTION, + {optstr: format("-%s", name)} + ) } } else if (this.optionTakesArg(option)) { break; @@ -482,8 +548,12 @@ Parser.prototype.parse = function parse(inputs) { break; } else { if (i + 1 >= args.length) { - throw new Error(format('do not have enough args ' - + 'for "-%s" option', name)); + throw augment_error( + new Error(format('do not have enough args ' + + 'for "-%s" option', name)), + ERRORS.ARG_TO_OPTION_MISSING, + {optstr: format("-%s", name)} + ) } addOpt(option, '-'+name, option.key, args[i + 1], 'argv'); i++; @@ -1051,5 +1121,9 @@ module.exports = { parseNumber: parseNumber, parseInteger: parseInteger, parsePositiveInteger: parsePositiveInteger, - parseDate: parseDate + parseDate: parseDate, + + // Export the error types + ERRORS: ERRORS, + augment_error: augment_error };