UNPKG

@jil/args

Version:

A convention based argument parsing and formatting library, with strict validation checks

177 lines (142 loc) 5.02 kB
import levenary from 'levenary'; import {COMMAND_FORMAT} from './constants'; import {ArgsError, ArgsErrorCode, ParseError} from './errors'; import { AliasMap, LongOptionName, OptionConfig, OptionConfigMap, ParamConfig, ShortOptionName, ValueType, } from './types'; import {ValidationError} from './ValidationError'; export class Checker { arg = ''; argIndex = 0; options: OptionConfigMap; parseErrors: ParseError[] = []; validationErrors: ValidationError[] = []; constructor(options: OptionConfigMap) { this.options = options; } checkCommandOrder(anotherCommand: string, providedCommand: string, paramsLength: number) { if (providedCommand !== '') { this.logFailureError('COMMAND_PROVIDED', [providedCommand, anotherCommand]); } else if (paramsLength !== 0) { this.logFailureError('COMMAND_NOT_FIRST'); } } checkNoInlineValue(inlineValue?: string) { if (inlineValue !== undefined) { this.logFailureError('VALUE_NO_INLINE'); } } checkUnknownOption(option: LongOptionName | ShortOptionName) { const guess = levenary(option, Object.keys(this.options)); if (guess) { this.logFailureError('OPTION_UNKNOWN_MORE', [option, guess]); } else { this.logFailureError('OPTION_UNKNOWN', [option]); } } validateArityIsMet(option: LongOptionName, config: OptionConfig, value: ValueType) { if (!config.arity || !Array.isArray(value)) { return; } if (value.length > 0 && value.length !== config.arity) { this.logInvalidError('VALUE_INVALID_ARITY', [config.arity, value.length], option); } } validateDefaultValue(option: LongOptionName, value: unknown, config: OptionConfig) { if (config.multiple) { if (!Array.isArray(value)) { this.logInvalidError('VALUE_NON_ARRAY', [option], option); } return; } if (config.type === 'boolean' && typeof value !== 'boolean') { this.logInvalidError('VALUE_NON_BOOL', [option], option); } if (config.type === 'number' && typeof value !== 'number') { this.logInvalidError('VALUE_NON_NUMBER', [option], option); } if (config.type === 'string' && typeof value !== 'string') { this.logInvalidError('VALUE_NON_STRING', [option], option); } } validateChoiceIsMet(option: LongOptionName, config: OptionConfig, value: ValueType) { if (value && Array.isArray(config.choices) && !config.choices.includes(value as 'string')) { this.logInvalidError('VALUE_INVALID_CHOICE', [config.choices.join(', '), value || '""'], option); } } validateCommandFormat(command: string) { if (!COMMAND_FORMAT.test(command)) { this.logInvalidError('COMMAND_INVALID_FORMAT', [command]); } } validateNumberCount(option: LongOptionName, config: OptionConfig) { if (config.count && config.type !== 'number') { this.logInvalidError('OPTION_INVALID_COUNT_TYPE', [], option); } } validateParsedOption(option: LongOptionName, config: OptionConfig, value: unknown) { if (config.validate) { try { config.validate(value); } catch (error: unknown) { this.logInvalid((error as Error).message, option); } } } validateParsedParam(config: ParamConfig, value: unknown) { if (config.validate) { try { config.validate(value); } catch (error: unknown) { this.logInvalid((error as Error).message); } } if (config.required && value === undefined) { this.logInvalidError('PARAM_REQUIRED', [config.label]); } } validateParamOrder(configs: ParamConfig[]) { const optionals: ParamConfig[] = []; configs.forEach(config => { if (config.required) { if (optionals.length > 0) { const labels = optionals.map(opt => `"${opt.label}"`); this.logInvalidError('PARAM_INVALID_ORDER', [labels.join(', '), config.label]); } } else { optionals.push(config); } }); } validateRequiredParamNoDefault(config: ParamConfig) { if (config.required && config.default !== undefined) { this.logInvalidError('PARAM_REQUIRED_NO_DEFAULT', [config.label]); } } validateUniqueShortName(option: LongOptionName, short: ShortOptionName, map: AliasMap) { if (map[short]) { this.logInvalidError('SHORT_DEFINED', [short, map[short]], option); } if (short.length !== 1) { this.logInvalidError('SHORT_INVALID_CHAR', [short], option); } } logFailureError(code: ArgsErrorCode, args?: unknown[]) { this.logFailure(new ArgsError(code, args).message); } logFailure(message: string) { this.parseErrors.push(new ParseError(message, this.arg, this.argIndex)); } logInvalidError(code: ArgsErrorCode, args?: unknown[], option?: LongOptionName) { this.logInvalid(new ArgsError(code, args).message, option); } logInvalid(message: string, option?: LongOptionName) { this.validationErrors.push(new ValidationError(message, option)); } }