♻ Move argument parsing into separate function

This commit is contained in:
C-3PO 2018-10-24 18:19:36 +02:00
parent cb67bc6220
commit 20315cc64f
Signed by: c3po
GPG key ID: 62993C4BB4D86F24
2 changed files with 70 additions and 56 deletions

View file

@ -1,7 +1,7 @@
import initState from './initState'; import initState from './initState';
import IOption from './IOption'; import IOption from './IOption';
import parseArgument from './parseArgument';
import runPreParseHook from './runPreParseHook'; import runPreParseHook from './runPreParseHook';
import verifyAndStoreOptionValue from './verifyAndStoreOptionValue';
/** /**
* 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. * 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.
@ -19,63 +19,11 @@ export default function parseArguments(
//Iterate through all command line arguments. When we have read both name and value, verify the argument for correctness. //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. //Show error if a name has no value afterwards, or a value has no name in front of it.
let option = ''; const lastOption = args.reduce(parseArgument.bind(null, { spec, fail, outputArgs, requiredOptions, shortToLongLookup }));
for (const arg of args) {
if (option === '') {
/** We expect a name, must be one of:
* - `--name value`
* - `--name=value`
* - `-n value`
* - `-n=value`
*/
if (arg === '-' || arg === '--') {
fail(`Empty option "-" or "--" is not supported.`);
} else if (arg.startsWith('--')) { //long argument
option = arg.substr(2);
let value;
//If there's a =, immediately read the value
if (option.indexOf('=') !== -1) {
[option, value] = option.split('=', 2);
}
//Check that argument name is valid
if (spec[option] === undefined) {
fail(`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});
option = '';
}
} else if (arg.startsWith('-')) { //short argument
option = arg.substr(1);
let value;
//If there's a =, immediately read the value
if (option.indexOf('=') !== -1) {
[option, value] = option.split('=', 2);
}
//Check that argument name is valid
if (shortToLongLookup[option] === undefined) {
fail(`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});
option = '';
}
} else {
fail(`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, value: arg, verify: spec[option].verify, message: spec[option].message, fail, outputArgs, requiredOptions});
option = '';
}
}
// argumentName must be cleared to '' after the value is read, so if it is not an empty string, the value was missing // argumentName must be cleared to '' after the value is read, so if it is not an empty string, the value was missing
if (option !== '') { if (lastOption !== '') {
fail(`Option "${option}" was not followed by a value.`); fail(`Option "${lastOption}" was not followed by a value.`);
} }
//check if any entry in requiredArguments was not set //check if any entry in requiredArguments was not set

66
src/parseArgument.ts Normal file
View file

@ -0,0 +1,66 @@
import IOption from './IOption';
import verifyAndStoreOptionValue from './verifyAndStoreOptionValue';
export default function parseArgument(
{ spec, fail, outputArgs, requiredOptions, shortToLongLookup }: {
spec: { [key: string]: IOption },
fail: (errorMessage: string) => void,
outputArgs: { [key: string]: string },
requiredOptions: { [key: string]: boolean },
shortToLongLookup: { [key: string]: string },
},
option: string,
arg: string,
): string {
if (option === '') {
/** We expect a name, must be one of:
* - `--name value`
* - `--name=value`
* - `-n value`
* - `-n=value`
*/
if (arg === '-' || arg === '--') {
fail(`Empty option "-" or "--" is not supported.`);
} else if (arg.startsWith('--')) { //long argument
option = arg.substr(2);
let value;
//If there's a =, immediately read the value
if (option.indexOf('=') !== -1) {
[option, value] = option.split('=', 2);
}
//Check that argument name is valid
if (spec[option] === undefined) {
fail(`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});
option = '';
}
} else if (arg.startsWith('-')) { //short argument
option = arg.substr(1);
let value;
//If there's a =, immediately read the value
if (option.indexOf('=') !== -1) {
[option, value] = option.split('=', 2);
}
//Check that argument name is valid
if (shortToLongLookup[option] === undefined) {
fail(`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});
option = '';
}
} else {
fail(`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, value: arg, verify: spec[option].verify, message: spec[option].message, fail, outputArgs, requiredOptions});
option = '';
}
return option;
}