2018-10-24 04:39:04 +02:00
|
|
|
import initState from './initState';
|
|
|
|
import IOption from './IOption';
|
2018-10-24 18:19:36 +02:00
|
|
|
import parseArgument from './parseArgument';
|
2018-10-24 04:39:04 +02:00
|
|
|
import runPreParseHook from './runPreParseHook';
|
2018-10-23 23:17:03 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* 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[], fail: (message: string) => void) => (string[] | undefined),
|
2018-10-25 04:01:00 +02:00
|
|
|
): { fail: (errorMessage: string) => never, args: { [key: string]: string } } {
|
2018-10-24 04:39:04 +02:00
|
|
|
//Initialize state
|
2018-10-24 04:44:49 +02:00
|
|
|
const { outputArgs, shortToLongLookup, requiredOptions, fail } = initState(spec);
|
|
|
|
const args = runPreParseHook({ args: process.argv.slice(2), preParseHook, fail });
|
2018-10-23 23:17:03 +02:00
|
|
|
|
|
|
|
//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.
|
2018-10-24 18:19:36 +02:00
|
|
|
const lastOption = args.reduce(parseArgument.bind(null, { spec, fail, outputArgs, requiredOptions, shortToLongLookup }));
|
2018-10-23 23:17:03 +02:00
|
|
|
|
|
|
|
// argumentName must be cleared to '' after the value is read, so if it is not an empty string, the value was missing
|
2018-10-24 18:19:36 +02:00
|
|
|
if (lastOption !== '') {
|
2018-10-25 04:34:11 +02:00
|
|
|
return fail(`Option "${lastOption}" was not followed by a value.`);
|
2018-10-23 23:17:03 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//check if any entry in requiredArguments was not set
|
|
|
|
for (const optName in requiredOptions) {
|
|
|
|
if (spec.hasOwnProperty(optName) && requiredOptions[optName] === false) {
|
2018-10-25 04:34:11 +02:00
|
|
|
return fail(`Missing option "${optName}" even though it is required.`);
|
2018-10-23 23:17:03 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return {
|
2018-10-24 04:44:49 +02:00
|
|
|
fail,
|
2018-10-23 23:17:03 +02:00
|
|
|
args: outputArgs,
|
|
|
|
};
|
|
|
|
}
|