♻ 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 IOption from './IOption';
|
||||
import IOption from './interfaces/IOption';
|
||||
import parseArgument from './parseArgument';
|
||||
import runPreParseHook from './runPreParseHook';
|
||||
|
||||
|
@ -28,11 +28,9 @@ export default function parseArguments(
|
|||
}
|
||||
|
||||
//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.`);
|
||||
}
|
||||
}
|
||||
Object.entries(requiredOptions).filter(([, wasFound]) => wasFound === false).forEach(([option]) => {
|
||||
throw new Error(`Missing option "${option}" even though it is required.`);
|
||||
});
|
||||
} catch (error) {
|
||||
fail((error as Error).message);
|
||||
}
|
||||
|
|
|
@ -1,40 +1,19 @@
|
|||
import failWithError from './failWithError';
|
||||
import IOption from './IOption';
|
||||
|
||||
const failFunction: (error?: string) => never = failWithError.bind(null, '');
|
||||
import IOption from './interfaces/IOption';
|
||||
import IState from './interfaces/IState';
|
||||
import parseSpecEntry from './parseSpecEntry';
|
||||
|
||||
export default function initState(spec: { [key: string]: IOption }) {
|
||||
//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
|
||||
const shortToLongLookup: { [key: string]: string } = {};
|
||||
const requiredOptions: { [key: string]: boolean } = {};
|
||||
for (const longOption in spec) {
|
||||
if (spec.hasOwnProperty(longOption)) {
|
||||
if (longOption === '') {
|
||||
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]+)*$/)) {
|
||||
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 shortToLongLookup: IState['shortToLongLookup'] = {};
|
||||
const requiredOptions: IState['requiredOptions'] = {};
|
||||
try {
|
||||
Object.entries(spec).forEach(parseSpecEntry.bind(null, { outputArgs, shortToLongLookup, requiredOptions }));
|
||||
} catch (error) {
|
||||
failWithError('', (error as Error).message);
|
||||
}
|
||||
|
||||
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';
|
||||
|
||||
export default function parseArgument(
|
||||
{ spec, outputArgs, requiredOptions, shortToLongLookup }: {
|
||||
spec: { [key: string]: IOption },
|
||||
outputArgs: { [key: string]: string },
|
||||
requiredOptions: { [key: string]: boolean },
|
||||
shortToLongLookup: { [key: string]: string },
|
||||
outputArgs: IState['outputArgs'],
|
||||
requiredOptions: IState['requiredOptions'],
|
||||
shortToLongLookup: IState['shortToLongLookup'],
|
||||
},
|
||||
previousOption: 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({
|
||||
option,
|
||||
|
@ -12,8 +13,8 @@ export default function verifyAndStoreOptionValue({
|
|||
value: string,
|
||||
verify: IOption['verify'],
|
||||
message: IOption['message'],
|
||||
outputArgs: { [key: string]: string },
|
||||
requiredOptions: { [key: string]: boolean },
|
||||
outputArgs: IState['outputArgs'],
|
||||
requiredOptions: IState['requiredOptions'],
|
||||
}) {
|
||||
//Verify value for correctness
|
||||
try {
|
||||
|
|
Loading…
Reference in a new issue