diff --git a/src/index.ts b/src/index.ts index 3e0b431..f5e8caf 100644 --- a/src/index.ts +++ b/src/index.ts @@ -11,26 +11,30 @@ import runPreParseHook from './runPreParseHook'; */ export default function parseArguments( spec: { [key: string]: IOption }, - preParseHook?: (args: string[], fail: (message: string) => void) => (string[] | undefined), + preParseHook?: (args: string[]) => (string[] | undefined), ): { fail: (errorMessage: string) => never, args: { [key: string]: string } } { //Initialize state const { outputArgs, shortToLongLookup, requiredOptions, fail } = initState(spec); - const args = runPreParseHook({ args: process.argv.slice(2), preParseHook, fail }); + try { + const args = runPreParseHook({ args: process.argv.slice(2), preParseHook }); - //Iterate through all command line arguments. When we have read both name and value, verify the argument for correctness. - //Show error if a name has no value afterwards, or a value has no name in front of it. - const lastOption = args.reduce(parseArgument.bind(null, { spec, fail, outputArgs, requiredOptions, shortToLongLookup })); + //Iterate through all command line arguments. When we have read both name and value, verify the argument for correctness. + //Show error if a name has no value afterwards, or a value has no name in front of it. + const lastOption = args.reduce(parseArgument.bind(null, { spec, outputArgs, requiredOptions, shortToLongLookup })); - // argumentName must be cleared to '' after the value is read, so if it is not an empty string, the value was missing - if (lastOption !== '') { - return fail(`Option "${lastOption}" was not followed by a value.`); - } - - //check if any entry in requiredArguments was not set - for (const optName in requiredOptions) { - if (spec.hasOwnProperty(optName) && requiredOptions[optName] === false) { - return fail(`Missing option "${optName}" even though it is required.`); + // argumentName must be cleared to '' after the value is read, so if it is not an empty string, the value was missing + if (lastOption !== '') { + throw new Error(`Option "${lastOption}" was not followed by a value.`); } + + //check if any entry in requiredArguments was not set + for (const optName in requiredOptions) { + if (spec.hasOwnProperty(optName) && requiredOptions[optName] === false) { + throw new Error(`Missing option "${optName}" even though it is required.`); + } + } + } catch (error) { + fail((error as Error).message); } return { diff --git a/src/parseArgument.ts b/src/parseArgument.ts index 963c64f..4c07c0b 100644 --- a/src/parseArgument.ts +++ b/src/parseArgument.ts @@ -2,9 +2,8 @@ import IOption from './IOption'; import verifyAndStoreOptionValue from './verifyAndStoreOptionValue'; export default function parseArgument( - { spec, fail, outputArgs, requiredOptions, shortToLongLookup }: { + { spec, outputArgs, requiredOptions, shortToLongLookup }: { spec: { [key: string]: IOption }, - fail: (errorMessage: string) => never, outputArgs: { [key: string]: string }, requiredOptions: { [key: string]: boolean }, shortToLongLookup: { [key: string]: string }, @@ -20,7 +19,7 @@ export default function parseArgument( * - `-o=value` */ if (arg === '-' || arg === '--') { - return fail(`Empty option "-" or "--" is not supported.`); + throw new Error(`Empty option "-" or "--" is not supported.`); } else if (arg.startsWith('--')) { //long argument let option = arg.substr(2); let value; @@ -30,11 +29,11 @@ export default function parseArgument( } //Check that argument name is valid if (spec[option] === undefined) { - return fail(`Unknown option "--${option}".`); + throw new Error(`Unknown option "--${option}".`); } //If value was provided, check that value is correct and remove name for next loop iteration if (value !== undefined) { - verifyAndStoreOptionValue({option, value, verify: spec[option].verify, message: spec[option].message, fail, outputArgs, requiredOptions}); + verifyAndStoreOptionValue({option, value, verify: spec[option].verify, message: spec[option].message, outputArgs, requiredOptions}); return ''; } return option; @@ -47,20 +46,20 @@ export default function parseArgument( } //Check that argument name is valid if (shortToLongLookup[option] === undefined) { - return fail(`Unknown short option "-${option}".`); + throw new Error(`Unknown short option "-${option}".`); } option = shortToLongLookup[option]; //If value was provided, check that value is correct and remove name for next loop iteration if (value !== undefined) { - verifyAndStoreOptionValue({option, value, verify: spec[option].verify, message: spec[option].message, fail, outputArgs, requiredOptions}); + verifyAndStoreOptionValue({option, value, verify: spec[option].verify, message: spec[option].message, outputArgs, requiredOptions}); return ''; } return option; } else { - return fail(`Arguments must be preceded by an option but there was no option in front of "${arg}".`); + throw new Error(`Arguments must be preceded by an option but there was no option in front of "${arg}".`); } } else { //We expect a value, can be anything - verifyAndStoreOptionValue({option: previousOption, value: arg, verify: spec[previousOption].verify, message: spec[previousOption].message, fail, outputArgs, requiredOptions}); + verifyAndStoreOptionValue({option: previousOption, value: arg, verify: spec[previousOption].verify, message: spec[previousOption].message, outputArgs, requiredOptions}); return ''; } } diff --git a/src/runPreParseHook.ts b/src/runPreParseHook.ts index d2542a2..cb61181 100644 --- a/src/runPreParseHook.ts +++ b/src/runPreParseHook.ts @@ -1,17 +1,16 @@ /** Runs the given pre-parse hook, if defined, to modify the command line arguments. Returns the modified command line arguments. */ -export default function runPreParseHook({ args, preParseHook, fail }: { +export default function runPreParseHook({ args, preParseHook }: { args: string[], - preParseHook?: (args: string[], fail: (message: string) => void) => (string[] | undefined), - fail: (errorMessage: string) => never, + preParseHook?: (args: string[]) => (string[] | undefined), }): string[] { if (preParseHook === undefined) { return args; } try { - const modifiedArgs = preParseHook(args, fail); + const modifiedArgs = preParseHook(args); return modifiedArgs !== undefined ? modifiedArgs : args; } catch (error) { - return fail(`Could not run pre-parse hook, encountered error: ${String(error)}.`); + throw new Error(`Could not run pre-parse hook, encountered error: ${String(error)}.`); } } diff --git a/src/verifyAndStoreOptionValue.ts b/src/verifyAndStoreOptionValue.ts index ef41238..3b64317 100644 --- a/src/verifyAndStoreOptionValue.ts +++ b/src/verifyAndStoreOptionValue.ts @@ -5,7 +5,6 @@ export default function verifyAndStoreOptionValue({ value, verify, message, - fail, outputArgs, requiredOptions, }: { @@ -13,7 +12,6 @@ export default function verifyAndStoreOptionValue({ value: string, verify: IOption['verify'], message: IOption['message'], - fail: (errorMessage: string) => never, outputArgs: { [key: string]: string }, requiredOptions: { [key: string]: boolean }, }) { @@ -24,16 +22,16 @@ export default function verifyAndStoreOptionValue({ try { const customMessage = message(value); if (customMessage !== undefined && customMessage !== '') { - return fail(customMessage); + throw new Error(customMessage); } } catch (error) { - return fail(`Invalid value set for option "${option}": "${value}". Could not show custom error message: ${String(error)}`); + throw new Error(`Invalid value set for option "${option}": "${value}". Could not show custom error message: ${String(error)}`); } } - return fail(`Invalid value set for option "${option}": "${value}".`); + throw new Error(`Invalid value set for option "${option}": "${value}".`); } } catch (error) { - return fail(`Invalid value set for option "${option}", the validation of "${value}" failed: ${String(error)}`); + throw new Error(`Invalid value set for option "${option}", the validation of "${value}" failed: ${String(error)}`); } //Remember the value, and if it is a required argument, mark that we have encountered it