Rewrite: Make it a class, and add some methods for basic validation
This commit is contained in:
parent
e061fb0e76
commit
0d2224eba7
88
argparser.js
88
argparser.js
|
|
@ -1,5 +1,3 @@
|
|||
module.exports = parse;
|
||||
|
||||
// https://unix.stackexchange.com/questions/364383/confusion-about-changing-meaning-of-arguments-and-options-is-there-an-official
|
||||
// https://pubs.opengroup.org/onlinepubs/9699919799.2018edition/basedefs/V1_chap12.html#tag_12_01
|
||||
|
||||
|
|
@ -11,11 +9,89 @@ module.exports = parse;
|
|||
// 'operands' are (non-option) things that follow an option, but aren't option-arguments
|
||||
// eg 'filename.txt' in './example --verbose filename.txt'
|
||||
|
||||
const defaultErrorMessages = {
|
||||
missingRequiredOption: (optionName) => `Missing required option '${optionName}'`,
|
||||
missingRequiredArgument: (optionName) => `Missing argument for option ${optionName}`,
|
||||
tooManyArguments: (optionName) => `Too many arguments for option ${optionName}`,
|
||||
}
|
||||
|
||||
|
||||
module.exports = class Opts {
|
||||
constructor(argv) {
|
||||
this.opts = get(argv);
|
||||
this.synonyms = [];
|
||||
}
|
||||
|
||||
// TODO equip prototype with ability to print directly through `console.log(opts)`
|
||||
|
||||
/**
|
||||
* Declare multiple option flags to be synonymous.
|
||||
* Use this if you have short and long names for the same flag
|
||||
* eg: '-d' and '--debug'
|
||||
*
|
||||
* @param {Array<string>} namesWithDashes
|
||||
* @returns {void}
|
||||
**/
|
||||
synonymize(...namesWithDashes) {
|
||||
const names = namesWithDashes.map(n => stripDashes(n));
|
||||
names.forEach((n) => {
|
||||
const others = names.filter(x => x != n)
|
||||
this.synonyms[n] = others;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify the presence of a required option
|
||||
* @param {string} nameWithDashes
|
||||
* @param {string} [errorMessage]
|
||||
* @returns {Boolean} **True** indicates that the option is present
|
||||
**/
|
||||
requireOption(nameWithDashes, errorMessage=null) {
|
||||
const name = stripDashes(nameWithDashes);
|
||||
console.log('req opt name:', name);
|
||||
if (name in this.opts) return true;
|
||||
if (name in this.synonyms) {
|
||||
let syns = this.synonyms[name];
|
||||
console.log('syns', syns);
|
||||
let hits = syns.filter(s => s in this.opts ).length;
|
||||
if (hits > 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
throw new Error(errorMessage || defaultErrorMessages.missingRequiredOption(nameWithDashes));
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify the presence of arguments for an option that requires them,
|
||||
* if that option is present
|
||||
* @param {string} nameWithDashes
|
||||
* @param {number} [minRequired]
|
||||
* @param {number} [maxRequired]
|
||||
* @param {string} [tooFewMessage] Error message if there are too few arguments provided
|
||||
* @param {string} [tooManyMessage] Error message if there are too many arguments provided
|
||||
* @returns {Boolean} **True** indicates that the arguments are present, or that the option is *not* present
|
||||
**/
|
||||
requireOptionArgument(nameWithDashes, minRequired=1, maxRequired=1, tooFewMessage=null, tooManyMessage=null) {
|
||||
let name = stripDashes(nameWithDashes);
|
||||
if (name in this.opts) {
|
||||
console.log('type', typeof this.opts[name] === 'boolean');
|
||||
console.log(this.opts[name]);
|
||||
if (typeof this.opts[name] === 'boolean') {
|
||||
throw new Error(tooFewMessage || defaultErrorMessages.missingRequiredArgument(nameWithDashes));
|
||||
} else if (this.opts[name].length < minRequired) {
|
||||
throw new Error(tooFewMessage || defaultErrorMessages.missingRequiredArgument(nameWithDashes));
|
||||
} else if (this.opts[name].length > maxRequired) {
|
||||
throw new Error(tooManyMessage || defaultErrorMessages.tooManyArguments(nameWithDashes));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns [ string: (boolean | string[]) ]
|
||||
**/
|
||||
function parse(argv) {
|
||||
function get(argv) {
|
||||
argv = process.argv.slice(2);
|
||||
|
||||
// Label everything in argv as either
|
||||
|
|
@ -78,4 +154,10 @@ function parse(argv) {
|
|||
}
|
||||
});
|
||||
return out;
|
||||
}
|
||||
|
||||
function stripDashes(optionName) {
|
||||
if (optionName.startsWith('--')) return optionName.substring(2);
|
||||
if (optionName.startsWith('-')) return optionName.substring(1);
|
||||
return optionName;
|
||||
}
|
||||
79
test.js
79
test.js
|
|
@ -1,3 +1,78 @@
|
|||
const args = require('./argparser.js')(process.argv);
|
||||
const Opter = require('./argparser.js');
|
||||
|
||||
console.log(args);
|
||||
// const args = argparser.parse(process.argv);
|
||||
// console.log('args', args);
|
||||
// console.log('args', args);
|
||||
// requireOption(args, '--i');
|
||||
// argsrequire(args, '-i');
|
||||
|
||||
const opts = new Opter(process.argv)
|
||||
opts.synonymize('-i', '--input');
|
||||
opts.requireOption('-i');
|
||||
opts.requireOptionArgument('-i');
|
||||
console.log(opts.opts);
|
||||
|
||||
// const _defaultErrorMessages = {
|
||||
// missingRequiredOption: (optionName) => `Missing required option '${optionName}'`,
|
||||
// missingRequiredArgument: (optionName) => `Missing argument for option ${optionName}`,
|
||||
// tooManyArguments: (optionName) => `Too many arguments for option ${optionName}`,
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * Declare multiple option flags to be synonymous.
|
||||
// * Use this if you have short and long names for the same flag
|
||||
// * eg: '-d' and '--debug'
|
||||
// *
|
||||
// * @param {Array<string>} namesWithDashes
|
||||
// * @returns {void}
|
||||
// **/
|
||||
// function synonymize(opts /* <-- TODO tmp */, ...namesWithDashes) {
|
||||
// namesWithDashes.slice(1).forEach((n) => {
|
||||
// const x = _stripDashes(n);
|
||||
// this.opts[x] = opts[namesWithDashes[0]]; // TODO check 'this' works
|
||||
// });
|
||||
// }
|
||||
//
|
||||
// function _stripDashes(optionName) {
|
||||
// if (optionName.startsWith('--')) return optionName.substring(2);
|
||||
// if (optionName.startsWith('-')) return optionName.substring(1);
|
||||
// return optionName;
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * Verify the presence of a required option
|
||||
// * @param {string} nameWithDashes
|
||||
// * @param {string} [errorMessage]
|
||||
// * @returns {Boolean} **True** indicates that the option is present
|
||||
// **/
|
||||
// function requireOption(userProvidedOpts, nameWithDashes, errorMessage=null) {
|
||||
// if (_stripDashes(nameWithDashes) in userProvidedOpts) return true;
|
||||
// throw new Error(errorMessage || _defaultErrorMessages.missingRequiredOption(nameWithDashes));
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * Verify the presence of arguments for an option that requires them,
|
||||
// * if that option is present
|
||||
// * @param {string} nameWithDashes
|
||||
// * @param {number} [minRequired]
|
||||
// * @param {number} [maxRequired]
|
||||
// * @param {string} [tooFewMessage] Error message if there are too few arguments provided
|
||||
// * @param {string} [tooManyMessage] Error message if there are too many arguments provided
|
||||
// * @returns {Boolean} **True** indicates that the arguments are present, or that the option is *not* present
|
||||
// **/
|
||||
// // TODO remove first param when making this a method on an Args object
|
||||
// function argsrequire(userProvidedArgs, nameWithDashes, minRequired=1, maxRequired=1, tooFewMessage=null, tooManyMessage=null) {
|
||||
// let name = _stripDashes(nameWithDashes);
|
||||
// if (name in userProvidedArgs) {
|
||||
// console.log('type', typeof userProvidedArgs[name] === 'boolean');
|
||||
// console.log(userProvidedArgs[name]);
|
||||
// if (typeof userProvidedArgs[name] === 'boolean') {
|
||||
// throw new Error(tooFewMessage || _defaultErrorMessages.missingRequiredArgument(nameWithDashes));
|
||||
// } else if (userProvidedArgs[name].length < minRequired) {
|
||||
// throw new Error(tooFewMessage || _defaultErrorMessages.missingRequiredArgument(nameWithDashes));
|
||||
// } else if (userProvidedArgs[name].length > maxRequired) {
|
||||
// throw new Error(tooManyMessage || _defaultErrorMessages.tooManyArguments(nameWithDashes));
|
||||
// }
|
||||
// }
|
||||
// return true;
|
||||
// }
|
||||
Loading…
Reference in New Issue