import initState from './initState'; import IOption from './interfaces/IOption'; import parseArgument from './parseArgument'; import runPreParseHook from './runPreParseHook'; /** * Checks the command line arguments against the given specification, and returns the arguments as a JavaScript object, as well as a failure function that prints the usage instructions before terminating. * If an error is found, outputs an error message and terminates with a non-zero exit code. * @param spec A specification of what arguments are expected. * @param preParseHook Optionally, a function to modify the command line arguments before parsing them. */ export default function parseArguments( spec: { [key: string]: IOption }, preParseHook?: (args: string[]) => (string[] | undefined), ): { fail: (errorMessage: string) => never, args: { [key: string]: string } } { //Initialize state const { outputArgs, shortToLongLookup, requiredOptions, fail } = initState(spec); 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, 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 !== '') { throw new Error(`Option "${lastOption}" was not followed by a value.`); } //check if any entry in requiredArguments was not set Object.entries(requiredOptions).filter(([, wasFound]) => wasFound === false).forEach(([option]) => { throw new Error(`Missing option "${option}" even though it is required.`); }); } catch (error) { fail((error as Error).message); } return { fail, args: outputArgs, }; }