♻ Replace for statements by functions
This commit is contained in:
parent
640c8df6bc
commit
3ac2874912
7 changed files with 56 additions and 44 deletions
10
src/index.ts
10
src/index.ts
|
@ -1,5 +1,5 @@
|
||||||
import initState from './initState';
|
import initState from './initState';
|
||||||
import IOption from './IOption';
|
import IOption from './interfaces/IOption';
|
||||||
import parseArgument from './parseArgument';
|
import parseArgument from './parseArgument';
|
||||||
import runPreParseHook from './runPreParseHook';
|
import runPreParseHook from './runPreParseHook';
|
||||||
|
|
||||||
|
@ -28,11 +28,9 @@ export default function parseArguments(
|
||||||
}
|
}
|
||||||
|
|
||||||
//check if any entry in requiredArguments was not set
|
//check if any entry in requiredArguments was not set
|
||||||
for (const optName in requiredOptions) {
|
Object.entries(requiredOptions).filter(([, wasFound]) => wasFound === false).forEach(([option]) => {
|
||||||
if (spec.hasOwnProperty(optName) && requiredOptions[optName] === false) {
|
throw new Error(`Missing option "${option}" even though it is required.`);
|
||||||
throw new Error(`Missing option "${optName}" even though it is required.`);
|
});
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
fail((error as Error).message);
|
fail((error as Error).message);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,40 +1,19 @@
|
||||||
import failWithError from './failWithError';
|
import failWithError from './failWithError';
|
||||||
import IOption from './IOption';
|
import IOption from './interfaces/IOption';
|
||||||
|
import IState from './interfaces/IState';
|
||||||
const failFunction: (error?: string) => never = failWithError.bind(null, '');
|
import parseSpecEntry from './parseSpecEntry';
|
||||||
|
|
||||||
export default function initState(spec: { [key: string]: IOption }) {
|
export default function initState(spec: { [key: string]: IOption }) {
|
||||||
//The parsed arguments that are returned by this function
|
//The parsed arguments that are returned by this function
|
||||||
const outputArgs: { [key: string]: string } = {};
|
const outputArgs: IState['outputArgs'] = {};
|
||||||
|
|
||||||
//Create a lookup table to find a long option when given the short option, and to check if all required options are set
|
//Create a lookup table to find a long option when given the short option, and to check if all required options are set
|
||||||
const shortToLongLookup: { [key: string]: string } = {};
|
const shortToLongLookup: IState['shortToLongLookup'] = {};
|
||||||
const requiredOptions: { [key: string]: boolean } = {};
|
const requiredOptions: IState['requiredOptions'] = {};
|
||||||
for (const longOption in spec) {
|
try {
|
||||||
if (spec.hasOwnProperty(longOption)) {
|
Object.entries(spec).forEach(parseSpecEntry.bind(null, { outputArgs, shortToLongLookup, requiredOptions }));
|
||||||
if (longOption === '') {
|
} catch (error) {
|
||||||
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.`);
|
failWithError('', (error as Error).message);
|
||||||
}
|
|
||||||
if (!longOption.match(/^[a-z0-9]+(-[a-z0-9]+)*$/)) {
|
|
||||||
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;
|
|
||||||
if (shortOption !== undefined && shortOption !== '') {
|
|
||||||
if (shortOption.length > 1) {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
//If a default value is given, use the default value (it can be overridden later), otherwise mark argument as being required
|
|
||||||
const defaultValue = spec[longOption].default;
|
|
||||||
if (defaultValue !== undefined) {
|
|
||||||
outputArgs[longOption] = defaultValue;
|
|
||||||
} else {
|
|
||||||
requiredOptions[longOption] = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const usage = `./${process.argv[1].substr(process.argv[1].lastIndexOf('/') + 1)} [options]\nOPTIONS\n${
|
const usage = `./${process.argv[1].substr(process.argv[1].lastIndexOf('/') + 1)} [options]\nOPTIONS\n${
|
||||||
|
|
8
src/interfaces/IState.ts
Normal file
8
src/interfaces/IState.ts
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
export default interface IState {
|
||||||
|
/** Stores the parsed arguments that are returned by the argument parser */
|
||||||
|
outputArgs: { [key: string]: string };
|
||||||
|
/** Lookup table from the short option names to their corresponding long option nmae */
|
||||||
|
shortToLongLookup: { [key: string]: string };
|
||||||
|
/** For each required option, store if the parser already encountered it. At the end of parsing, all entries must be set to true or the parser fails. */
|
||||||
|
requiredOptions: { [key: string]: boolean };
|
||||||
|
}
|
|
@ -1,12 +1,13 @@
|
||||||
import IOption from './IOption';
|
import IOption from './interfaces/IOption';
|
||||||
|
import IState from './interfaces/IState';
|
||||||
import verifyAndStoreOptionValue from './verifyAndStoreOptionValue';
|
import verifyAndStoreOptionValue from './verifyAndStoreOptionValue';
|
||||||
|
|
||||||
export default function parseArgument(
|
export default function parseArgument(
|
||||||
{ spec, outputArgs, requiredOptions, shortToLongLookup }: {
|
{ spec, outputArgs, requiredOptions, shortToLongLookup }: {
|
||||||
spec: { [key: string]: IOption },
|
spec: { [key: string]: IOption },
|
||||||
outputArgs: { [key: string]: string },
|
outputArgs: IState['outputArgs'],
|
||||||
requiredOptions: { [key: string]: boolean },
|
requiredOptions: IState['requiredOptions'],
|
||||||
shortToLongLookup: { [key: string]: string },
|
shortToLongLookup: IState['shortToLongLookup'],
|
||||||
},
|
},
|
||||||
previousOption: string,
|
previousOption: string,
|
||||||
arg: string,
|
arg: string,
|
||||||
|
|
25
src/parseSpecEntry.ts
Normal file
25
src/parseSpecEntry.ts
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
import IOption from './interfaces/IOption';
|
||||||
|
import IState from './interfaces/IState';
|
||||||
|
|
||||||
|
export default function parseSpecEntry({ outputArgs, requiredOptions, shortToLongLookup }: IState, [longOption, { short: shortOption, default: defaultValue }]: [string, IOption]) {
|
||||||
|
if (longOption === '') {
|
||||||
|
throw new Error(`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]+)*$/)) {
|
||||||
|
throw new Error(`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.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shortOption !== undefined && shortOption !== '') {
|
||||||
|
if (shortOption.length > 1) {
|
||||||
|
throw new Error(`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;
|
||||||
|
}
|
||||||
|
|
||||||
|
//If a default value is given, use the default value (it can be overridden later), otherwise mark argument as being required
|
||||||
|
if (defaultValue !== undefined) {
|
||||||
|
outputArgs[longOption] = defaultValue;
|
||||||
|
} else {
|
||||||
|
requiredOptions[longOption] = false;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
import IOption from './IOption';
|
import IOption from './interfaces/IOption';
|
||||||
|
import IState from './interfaces/IState';
|
||||||
|
|
||||||
export default function verifyAndStoreOptionValue({
|
export default function verifyAndStoreOptionValue({
|
||||||
option,
|
option,
|
||||||
|
@ -12,8 +13,8 @@ export default function verifyAndStoreOptionValue({
|
||||||
value: string,
|
value: string,
|
||||||
verify: IOption['verify'],
|
verify: IOption['verify'],
|
||||||
message: IOption['message'],
|
message: IOption['message'],
|
||||||
outputArgs: { [key: string]: string },
|
outputArgs: IState['outputArgs'],
|
||||||
requiredOptions: { [key: string]: boolean },
|
requiredOptions: IState['requiredOptions'],
|
||||||
}) {
|
}) {
|
||||||
//Verify value for correctness
|
//Verify value for correctness
|
||||||
try {
|
try {
|
||||||
|
|
Loading…
Reference in a new issue