♻ Always return fail function
This commit is contained in:
parent
e50b34c068
commit
76d9de1778
6 changed files with 30 additions and 30 deletions
|
@ -3,6 +3,7 @@ This module parses the command line arguments into a JavaScript object, and veri
|
||||||
The main goal is to keep all the complexity and error handling inside this module, so that all command line applications only need to provide a couple lines of specification and do not have to worry about verifying the input or checking for `undefined`.
|
The main goal is to keep all the complexity and error handling inside this module, so that all command line applications only need to provide a couple lines of specification and do not have to worry about verifying the input or checking for `undefined`.
|
||||||
|
|
||||||
# Installation
|
# Installation
|
||||||
|
|
||||||
For this tool to work, the TypeScript compiler must be globally installed:
|
For this tool to work, the TypeScript compiler must be globally installed:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|
|
@ -23,13 +23,13 @@ export default function parseArguments(
|
||||||
|
|
||||||
// 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 (lastOption !== '') {
|
if (lastOption !== '') {
|
||||||
fail(`Option "${lastOption}" was not followed by a value.`);
|
return 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
|
||||||
for (const optName in requiredOptions) {
|
for (const optName in requiredOptions) {
|
||||||
if (spec.hasOwnProperty(optName) && requiredOptions[optName] === false) {
|
if (spec.hasOwnProperty(optName) && requiredOptions[optName] === false) {
|
||||||
fail(`Missing option "${optName}" even though it is required.`);
|
return fail(`Missing option "${optName}" even though it is required.`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,16 +13,16 @@ export default function initState(spec: { [key: string]: IOption }) {
|
||||||
for (const longOption in spec) {
|
for (const longOption in spec) {
|
||||||
if (spec.hasOwnProperty(longOption)) {
|
if (spec.hasOwnProperty(longOption)) {
|
||||||
if (longOption === '') {
|
if (longOption === '') {
|
||||||
failFunction(`The long option may not be an empty string. This is a bug in the source code of the script that you tried to call.`);
|
return failFunction(`The long option may not be an empty string. This is a bug in the source code of the script that you tried to call.`);
|
||||||
}
|
}
|
||||||
if (!longOption.match(/^[a-z0-9]+(-[a-z0-9]+)*$/)) {
|
if (!longOption.match(/^[a-z0-9]+(-[a-z0-9]+)*$/)) {
|
||||||
failFunction(`The long option "${longOption}" must only contain alpha-numeric characters, optionally separated by hyphens. This is a bug in the source code of the script that you tried to call.`);
|
return failFunction(`The long option "${longOption}" must only contain alpha-numeric characters, optionally separated by hyphens. This is a bug in the source code of the script that you tried to call.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const shortOption = spec[longOption].short;
|
const shortOption = spec[longOption].short;
|
||||||
if (shortOption !== undefined && shortOption !== '') {
|
if (shortOption !== undefined && shortOption !== '') {
|
||||||
if (shortOption.length > 1) {
|
if (shortOption.length > 1) {
|
||||||
failFunction(`Short options must only be one character long but the short option "${shortOption}" for "${longOption}" was ${shortOption.length} characters long. This is a bug in the source code of the script that you tried to call.`);
|
return failFunction(`Short options must only be one character long but the short option "${shortOption}" for "${longOption}" was ${shortOption.length} characters long. This is a bug in the source code of the script that you tried to call.`);
|
||||||
}
|
}
|
||||||
shortToLongLookup[shortOption] = longOption;
|
shortToLongLookup[shortOption] = longOption;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,20 +9,20 @@ export default function parseArgument(
|
||||||
requiredOptions: { [key: string]: boolean },
|
requiredOptions: { [key: string]: boolean },
|
||||||
shortToLongLookup: { [key: string]: string },
|
shortToLongLookup: { [key: string]: string },
|
||||||
},
|
},
|
||||||
option: string,
|
previousOption: string,
|
||||||
arg: string,
|
arg: string,
|
||||||
): string {
|
): string {
|
||||||
if (option === '') {
|
if (previousOption === '') {
|
||||||
/** We expect a name, must be one of:
|
/** We expect an option, must be one of:
|
||||||
* - `--name value`
|
* - `--option value`
|
||||||
* - `--name=value`
|
* - `--option=value`
|
||||||
* - `-n value`
|
* - `-o value`
|
||||||
* - `-n=value`
|
* - `-o=value`
|
||||||
*/
|
*/
|
||||||
if (arg === '-' || arg === '--') {
|
if (arg === '-' || arg === '--') {
|
||||||
fail(`Empty option "-" or "--" is not supported.`);
|
return fail(`Empty option "-" or "--" is not supported.`);
|
||||||
} else if (arg.startsWith('--')) { //long argument
|
} else if (arg.startsWith('--')) { //long argument
|
||||||
option = arg.substr(2);
|
let option = arg.substr(2);
|
||||||
let value;
|
let value;
|
||||||
//If there's a =, immediately read the value
|
//If there's a =, immediately read the value
|
||||||
if (option.indexOf('=') !== -1) {
|
if (option.indexOf('=') !== -1) {
|
||||||
|
@ -30,15 +30,16 @@ export default function parseArgument(
|
||||||
}
|
}
|
||||||
//Check that argument name is valid
|
//Check that argument name is valid
|
||||||
if (spec[option] === undefined) {
|
if (spec[option] === undefined) {
|
||||||
fail(`Unknown option "--${option}".`);
|
return fail(`Unknown option "--${option}".`);
|
||||||
}
|
}
|
||||||
//If value was provided, check that value is correct and remove name for next loop iteration
|
//If value was provided, check that value is correct and remove name for next loop iteration
|
||||||
if (value !== undefined) {
|
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, fail, outputArgs, requiredOptions});
|
||||||
option = '';
|
return '';
|
||||||
}
|
}
|
||||||
|
return option;
|
||||||
} else if (arg.startsWith('-')) { //short argument
|
} else if (arg.startsWith('-')) { //short argument
|
||||||
option = arg.substr(1);
|
let option = arg.substr(1);
|
||||||
let value;
|
let value;
|
||||||
//If there's a =, immediately read the value
|
//If there's a =, immediately read the value
|
||||||
if (option.indexOf('=') !== -1) {
|
if (option.indexOf('=') !== -1) {
|
||||||
|
@ -46,21 +47,20 @@ export default function parseArgument(
|
||||||
}
|
}
|
||||||
//Check that argument name is valid
|
//Check that argument name is valid
|
||||||
if (shortToLongLookup[option] === undefined) {
|
if (shortToLongLookup[option] === undefined) {
|
||||||
fail(`Unknown short option "-${option}".`);
|
return fail(`Unknown short option "-${option}".`);
|
||||||
}
|
}
|
||||||
option = shortToLongLookup[option];
|
option = shortToLongLookup[option];
|
||||||
//If value was provided, check that value is correct and remove name for next loop iteration
|
//If value was provided, check that value is correct and remove name for next loop iteration
|
||||||
if (value !== undefined) {
|
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, fail, outputArgs, requiredOptions});
|
||||||
option = '';
|
return '';
|
||||||
}
|
}
|
||||||
|
return option;
|
||||||
} else {
|
} else {
|
||||||
fail(`Arguments must be preceded by an option but there was no option in front of "${arg}".`);
|
return 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
|
} else { //We expect a value, can be anything
|
||||||
verifyAndStoreOptionValue({option, value: arg, verify: spec[option].verify, message: spec[option].message, fail, outputArgs, requiredOptions});
|
verifyAndStoreOptionValue({option: previousOption, value: arg, verify: spec[previousOption].verify, message: spec[previousOption].message, fail, outputArgs, requiredOptions});
|
||||||
option = '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
return option;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,6 @@ export default function runPreParseHook({ args, preParseHook, fail }: {
|
||||||
const modifiedArgs = preParseHook(args, fail);
|
const modifiedArgs = preParseHook(args, fail);
|
||||||
return modifiedArgs !== undefined ? modifiedArgs : args;
|
return modifiedArgs !== undefined ? modifiedArgs : args;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
fail(`Could not run pre-parse hook, encountered error: ${String(error)}.`);
|
return fail(`Could not run pre-parse hook, encountered error: ${String(error)}.`);
|
||||||
return [];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,16 +24,16 @@ export default function verifyAndStoreOptionValue({
|
||||||
try {
|
try {
|
||||||
const customMessage = message(value);
|
const customMessage = message(value);
|
||||||
if (customMessage !== undefined && customMessage !== '') {
|
if (customMessage !== undefined && customMessage !== '') {
|
||||||
fail(customMessage);
|
return fail(customMessage);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
fail(`Invalid value set for option "${option}": "${value}". Could not show custom error message: ${String(error)}`);
|
return fail(`Invalid value set for option "${option}": "${value}". Could not show custom error message: ${String(error)}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fail(`Invalid value set for option "${option}": "${value}".`);
|
return fail(`Invalid value set for option "${option}": "${value}".`);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
fail(`Invalid value set for option "${option}", the validation of "${value}" failed: ${String(error)}`);
|
return fail(`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
|
//Remember the value, and if it is a required argument, mark that we have encountered it
|
||||||
|
|
Loading…
Reference in a new issue