From 20315cc64f7c576f7dc078e3d82e4045c063620f Mon Sep 17 00:00:00 2001 From: C-3PO Date: Wed, 24 Oct 2018 18:19:36 +0200 Subject: [PATCH] =?UTF-8?q?=E2=99=BB=20Move=20argument=20parsing=20into=20?= =?UTF-8?q?separate=20function?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/index.ts | 60 +++------------------------------------- src/parseArgument.ts | 66 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+), 56 deletions(-) create mode 100644 src/parseArgument.ts diff --git a/src/index.ts b/src/index.ts index 4ce023e..627e388 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,7 +1,7 @@ import initState from './initState'; import IOption from './IOption'; +import parseArgument from './parseArgument'; 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. @@ -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. //Show error if a name has no value afterwards, or a value has no name in front of it. - let option = ''; - 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 = ''; - } - - } + const lastOption = args.reduce(parseArgument.bind(null, { spec, fail, 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 (option !== '') { - fail(`Option "${option}" was not followed by a value.`); + if (lastOption !== '') { + fail(`Option "${lastOption}" was not followed by a value.`); } //check if any entry in requiredArguments was not set diff --git a/src/parseArgument.ts b/src/parseArgument.ts new file mode 100644 index 0000000..ec8704c --- /dev/null +++ b/src/parseArgument.ts @@ -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; +}