♻ Replace for statements by functions

This commit is contained in:
C-3PO 2018-10-25 06:42:39 +02:00
parent 640c8df6bc
commit 3ac2874912
Signed by: c3po
GPG key ID: 62993C4BB4D86F24
7 changed files with 56 additions and 44 deletions

View file

@ -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);
} }

View file

@ -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
View 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 };
}

View file

@ -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
View 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;
}
}

View file

@ -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 {