♻ Replace fail function by throwing error
This commit is contained in:
parent
76d9de1778
commit
640c8df6bc
4 changed files with 34 additions and 34 deletions
32
src/index.ts
32
src/index.ts
|
@ -11,26 +11,30 @@ import runPreParseHook from './runPreParseHook';
|
||||||
*/
|
*/
|
||||||
export default function parseArguments(
|
export default function parseArguments(
|
||||||
spec: { [key: string]: IOption },
|
spec: { [key: string]: IOption },
|
||||||
preParseHook?: (args: string[], fail: (message: string) => void) => (string[] | undefined),
|
preParseHook?: (args: string[]) => (string[] | undefined),
|
||||||
): { fail: (errorMessage: string) => never, args: { [key: string]: string } } {
|
): { fail: (errorMessage: string) => never, args: { [key: string]: string } } {
|
||||||
//Initialize state
|
//Initialize state
|
||||||
const { outputArgs, shortToLongLookup, requiredOptions, fail } = initState(spec);
|
const { outputArgs, shortToLongLookup, requiredOptions, fail } = initState(spec);
|
||||||
const args = runPreParseHook({ args: process.argv.slice(2), preParseHook, fail });
|
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.
|
//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.
|
||||||
const lastOption = args.reduce(parseArgument.bind(null, { spec, fail, outputArgs, requiredOptions, shortToLongLookup }));
|
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
|
// 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 !== '') {
|
||||||
return fail(`Option "${lastOption}" was not followed by a value.`);
|
throw new Error(`Option "${lastOption}" was not followed by a value.`);
|
||||||
}
|
|
||||||
|
|
||||||
//check if any entry in requiredArguments was not set
|
|
||||||
for (const optName in requiredOptions) {
|
|
||||||
if (spec.hasOwnProperty(optName) && requiredOptions[optName] === false) {
|
|
||||||
return fail(`Missing option "${optName}" even though it is required.`);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//check if any entry in requiredArguments was not set
|
||||||
|
for (const optName in requiredOptions) {
|
||||||
|
if (spec.hasOwnProperty(optName) && requiredOptions[optName] === false) {
|
||||||
|
throw new Error(`Missing option "${optName}" even though it is required.`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
fail((error as Error).message);
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -2,9 +2,8 @@ import IOption from './IOption';
|
||||||
import verifyAndStoreOptionValue from './verifyAndStoreOptionValue';
|
import verifyAndStoreOptionValue from './verifyAndStoreOptionValue';
|
||||||
|
|
||||||
export default function parseArgument(
|
export default function parseArgument(
|
||||||
{ spec, fail, outputArgs, requiredOptions, shortToLongLookup }: {
|
{ spec, outputArgs, requiredOptions, shortToLongLookup }: {
|
||||||
spec: { [key: string]: IOption },
|
spec: { [key: string]: IOption },
|
||||||
fail: (errorMessage: string) => never,
|
|
||||||
outputArgs: { [key: string]: string },
|
outputArgs: { [key: string]: string },
|
||||||
requiredOptions: { [key: string]: boolean },
|
requiredOptions: { [key: string]: boolean },
|
||||||
shortToLongLookup: { [key: string]: string },
|
shortToLongLookup: { [key: string]: string },
|
||||||
|
@ -20,7 +19,7 @@ export default function parseArgument(
|
||||||
* - `-o=value`
|
* - `-o=value`
|
||||||
*/
|
*/
|
||||||
if (arg === '-' || arg === '--') {
|
if (arg === '-' || arg === '--') {
|
||||||
return fail(`Empty option "-" or "--" is not supported.`);
|
throw new Error(`Empty option "-" or "--" is not supported.`);
|
||||||
} else if (arg.startsWith('--')) { //long argument
|
} else if (arg.startsWith('--')) { //long argument
|
||||||
let option = arg.substr(2);
|
let option = arg.substr(2);
|
||||||
let value;
|
let value;
|
||||||
|
@ -30,11 +29,11 @@ export default function parseArgument(
|
||||||
}
|
}
|
||||||
//Check that argument name is valid
|
//Check that argument name is valid
|
||||||
if (spec[option] === undefined) {
|
if (spec[option] === undefined) {
|
||||||
return fail(`Unknown option "--${option}".`);
|
throw new Error(`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, outputArgs, requiredOptions});
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
return option;
|
return option;
|
||||||
|
@ -47,20 +46,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) {
|
||||||
return fail(`Unknown short option "-${option}".`);
|
throw new Error(`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, outputArgs, requiredOptions});
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
return option;
|
return option;
|
||||||
} else {
|
} else {
|
||||||
return fail(`Arguments must be preceded by an option but there was no option in front of "${arg}".`);
|
throw new Error(`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: previousOption, value: arg, verify: spec[previousOption].verify, message: spec[previousOption].message, fail, outputArgs, requiredOptions});
|
verifyAndStoreOptionValue({option: previousOption, value: arg, verify: spec[previousOption].verify, message: spec[previousOption].message, outputArgs, requiredOptions});
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,17 +1,16 @@
|
||||||
/** Runs the given pre-parse hook, if defined, to modify the command line arguments. Returns the modified command line arguments. */
|
/** Runs the given pre-parse hook, if defined, to modify the command line arguments. Returns the modified command line arguments. */
|
||||||
export default function runPreParseHook({ args, preParseHook, fail }: {
|
export default function runPreParseHook({ args, preParseHook }: {
|
||||||
args: string[],
|
args: string[],
|
||||||
preParseHook?: (args: string[], fail: (message: string) => void) => (string[] | undefined),
|
preParseHook?: (args: string[]) => (string[] | undefined),
|
||||||
fail: (errorMessage: string) => never,
|
|
||||||
}): string[] {
|
}): string[] {
|
||||||
if (preParseHook === undefined) {
|
if (preParseHook === undefined) {
|
||||||
return args;
|
return args;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const modifiedArgs = preParseHook(args, fail);
|
const modifiedArgs = preParseHook(args);
|
||||||
return modifiedArgs !== undefined ? modifiedArgs : args;
|
return modifiedArgs !== undefined ? modifiedArgs : args;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return fail(`Could not run pre-parse hook, encountered error: ${String(error)}.`);
|
throw new Error(`Could not run pre-parse hook, encountered error: ${String(error)}.`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,6 @@ export default function verifyAndStoreOptionValue({
|
||||||
value,
|
value,
|
||||||
verify,
|
verify,
|
||||||
message,
|
message,
|
||||||
fail,
|
|
||||||
outputArgs,
|
outputArgs,
|
||||||
requiredOptions,
|
requiredOptions,
|
||||||
}: {
|
}: {
|
||||||
|
@ -13,7 +12,6 @@ export default function verifyAndStoreOptionValue({
|
||||||
value: string,
|
value: string,
|
||||||
verify: IOption['verify'],
|
verify: IOption['verify'],
|
||||||
message: IOption['message'],
|
message: IOption['message'],
|
||||||
fail: (errorMessage: string) => never,
|
|
||||||
outputArgs: { [key: string]: string },
|
outputArgs: { [key: string]: string },
|
||||||
requiredOptions: { [key: string]: boolean },
|
requiredOptions: { [key: string]: boolean },
|
||||||
}) {
|
}) {
|
||||||
|
@ -24,16 +22,16 @@ export default function verifyAndStoreOptionValue({
|
||||||
try {
|
try {
|
||||||
const customMessage = message(value);
|
const customMessage = message(value);
|
||||||
if (customMessage !== undefined && customMessage !== '') {
|
if (customMessage !== undefined && customMessage !== '') {
|
||||||
return fail(customMessage);
|
throw new Error(customMessage);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return fail(`Invalid value set for option "${option}": "${value}". Could not show custom error message: ${String(error)}`);
|
throw new Error(`Invalid value set for option "${option}": "${value}". Could not show custom error message: ${String(error)}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return fail(`Invalid value set for option "${option}": "${value}".`);
|
throw new Error(`Invalid value set for option "${option}": "${value}".`);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return fail(`Invalid value set for option "${option}", the validation of "${value}" failed: ${String(error)}`);
|
throw new Error(`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