UNPKG

aws-ddk-core

Version:

The AWS DataOps Development Kit is an open source development framework for customers that build data workflows and modern data architecture on AWS.

145 lines (118 loc) 3.89 kB
const flagSymbol = Symbol('arg flag'); function arg(opts, {argv = process.argv.slice(2), permissive = false, stopAtPositional = false} = {}) { if (!opts) { throw new Error('Argument specification object is required'); } const result = {_: []}; const aliases = {}; const handlers = {}; for (const key of Object.keys(opts)) { if (!key) { throw new TypeError('Argument key cannot be an empty string'); } if (key[0] !== '-') { throw new TypeError(`Argument key must start with '-' but found: '${key}'`); } if (key.length === 1) { throw new TypeError(`Argument key must have a name; singular '-' keys are not allowed: ${key}`); } if (typeof opts[key] === 'string') { aliases[key] = opts[key]; continue; } let type = opts[key]; let isFlag = false; if (Array.isArray(type) && type.length === 1 && typeof type[0] === 'function') { const [fn] = type; type = (value, name, prev = []) => { prev.push(fn(value, name, prev[prev.length - 1])); return prev; }; isFlag = fn === Boolean || fn[flagSymbol] === true; } else if (typeof type === 'function') { isFlag = type === Boolean || type[flagSymbol] === true; } else { throw new TypeError(`Type missing or not a function or valid array type: ${key}`); } if (key[1] !== '-' && key.length > 2) { throw new TypeError(`Short argument keys (with a single hyphen) must have only one character: ${key}`); } handlers[key] = [type, isFlag]; } for (let i = 0, len = argv.length; i < len; i++) { const wholeArg = argv[i]; if (stopAtPositional && result._.length > 0) { result._ = result._.concat(argv.slice(i)); break; } if (wholeArg === '--') { result._ = result._.concat(argv.slice(i + 1)); break; } if (wholeArg.length > 1 && wholeArg[0] === '-') { /* eslint-disable operator-linebreak */ const separatedArguments = (wholeArg[1] === '-' || wholeArg.length === 2) ? [wholeArg] : wholeArg.slice(1).split('').map(a => `-${a}`); /* eslint-enable operator-linebreak */ for (let j = 0; j < separatedArguments.length; j++) { const arg = separatedArguments[j]; const [originalArgName, argStr] = arg[1] === '-' ? arg.split(/=(.*)/, 2) : [arg, undefined]; let argName = originalArgName; while (argName in aliases) { argName = aliases[argName]; } if (!(argName in handlers)) { if (permissive) { result._.push(arg); continue; } else { const err = new Error(`Unknown or unexpected option: ${originalArgName}`); err.code = 'ARG_UNKNOWN_OPTION'; throw err; } } const [type, isFlag] = handlers[argName]; if (!isFlag && ((j + 1) < separatedArguments.length)) { throw new TypeError(`Option requires argument (but was followed by another short argument): ${originalArgName}`); } if (isFlag) { result[argName] = type(true, argName, result[argName]); } else if (argStr === undefined) { if ( argv.length < i + 2 || ( argv[i + 1].length > 1 && (argv[i + 1][0] === '-') && !( argv[i + 1].match(/^-?\d*(\.(?=\d))?\d*$/) && ( type === Number || // eslint-disable-next-line no-undef (typeof BigInt !== 'undefined' && type === BigInt) ) ) ) ) { const extended = originalArgName === argName ? '' : ` (alias for ${argName})`; throw new Error(`Option requires argument: ${originalArgName}${extended}`); } result[argName] = type(argv[i + 1], argName, result[argName]); ++i; } else { result[argName] = type(argStr, argName, result[argName]); } } } else { result._.push(wholeArg); } } return result; } arg.flag = fn => { fn[flagSymbol] = true; return fn; }; // Utility types arg.COUNT = arg.flag((v, name, existingCount) => (existingCount || 0) + 1); module.exports = arg;