added -version + rafactoring and tweaking...

Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
Alex A. Naanou 2020-07-01 17:28:10 +03:00
parent 5a9c087ca2
commit 8d7c8b0a1e
3 changed files with 59 additions and 34 deletions

View File

@ -28,7 +28,8 @@ This code is an evolution of that parser.
- Environment variable option/command values - Environment variable option/command values
env can control option defaults env can control option defaults
- Reasonable defaults - Reasonable defaults
- `-help` generator - `-help`
- '-version'
- common option aliases - common option aliases
- Extensible: - Extensible:
- Hooks for option value conversion _(XXX should this be implemented???)_ - Hooks for option value conversion _(XXX should this be implemented???)_

83
argv.js
View File

@ -38,19 +38,23 @@ module.ERROR =
//--------------------------------------------------------------------- //---------------------------------------------------------------------
// helpers... // helpers...
// XXX do we need to remove handlers???
// XXX does this need to be an event constructor???
var afterCallback = function(name){ var afterCallback = function(name){
var attr = '__after_'+ name var attr = '__after_'+ name
return function(func){ return function(func){
(this[attr] = this[attr] || []).push(func) var that = this
var args = [...arguments]
;(args.length == 1 && typeof(func) == 'function') ?
// add handler...
(this[attr] = this[attr] || []).push(func)
// call handlers...
: (this[attr] || [])
.forEach(function(func){
func.call(that, ...args) })
return this } } return this } }
var afterCallbackCall = function(name, context, ...args){
return (context['__after_'+ name] || [])
.forEach(function(func){
func.call(context, ...args) }) }
//--------------------------------------------------------------------- //---------------------------------------------------------------------
// Basic argv parser... // Basic argv parser...
@ -119,7 +123,8 @@ var afterCallbackCall = function(name, context, ...args){
// yet know of any error or stop conditions triggered later in the argv. // yet know of any error or stop conditions triggered later in the argv.
// //
// //
// XXX add support for - or -- stdin handling... (???) // XXX handle .required options...
// XXX handle option types???
// XXX add support for outputting strings instead of console.log(..) // XXX add support for outputting strings instead of console.log(..)
// XXX --help should work for any command and not just for the nested // XXX --help should work for any command and not just for the nested
// parser commands... (???) // parser commands... (???)
@ -234,11 +239,13 @@ object.Constructor('Parser', {
helpColumnPrefix: '- ', helpColumnPrefix: '- ',
// doc sections... // doc sections...
// XXX
version: undefined, version: undefined,
license: undefined,
usage: '$SCRIPTNAME [OPTIONS]', usage: '$SCRIPTNAME [OPTIONS]',
doc: undefined, doc: undefined,
examples: undefined, examples: undefined,
// XXX add license and version info...
//footer: '$SCRIPTNAME v:$VERSION',
footer: undefined, footer: undefined,
// XXX should wrap long lines... // XXX should wrap long lines...
@ -251,18 +258,22 @@ object.Constructor('Parser', {
[a +'\t'.repeat(opts_width - Math.floor(a.strip.length/8))+ prefix + b] [a +'\t'.repeat(opts_width - Math.floor(a.strip.length/8))+ prefix + b]
: [a, '\t'.repeat(opts_width)+ prefix + b]) : [a, '\t'.repeat(opts_width)+ prefix + b])
: [a] }, : [a] },
expandTextVars: function(text){
return text
.replace(/\$LICENSE/g, this.license || '')
.replace(/\$VERSION/g, this.version || '0.0.0')
.replace(/\$SCRIPTNAME/g, this.scriptName) },
// Builtin options/commands... // Builtin options/commands...
// XXX might be a good idea to keep short options in a separate column...
'-h': '-help', '-h': '-help',
'-help': { '-help': {
doc: 'print this message and exit.', doc: 'print this message and exit',
priority: 99, priority: 99,
handler: function(argv, key, value){ handler: function(argv, key, value){
var that = this var that = this
var expandVars = function(str){ var expandVars = this.expandTextVars.bind(this)
return str
.replace(/\$SCRIPTNAME/g, that.scriptName) }
var formDoc = function(doc, env){ var formDoc = function(doc, env){
return [doc, ...(env ? return [doc, ...(env ?
[`(default value: \$${env})`] [`(default value: \$${env})`]
@ -332,13 +343,31 @@ object.Constructor('Parser', {
.join('\n'))) .join('\n')))
return module.STOP }}, return module.STOP }},
'-v': '-version',
'-version': {
doc: 'show $SCRIPTNAME verion and exit',
priority: 99,
handler: function(){
console.log(this.version || '0.0.0')
return module.STOP }, },
/*/ XXX do we actually need this???
// doing this is trivial, need to give a practical example...
// XXX would be nice to be able to take the rest of the options and
// pass them to .then(..)...
'-': {
doc: 'stop processing arguments',
handler: function(){
return module.STOP }, },
//*/
// common short-hands... // common short-hands...
// //
// NOTE: defining this as a loop will enable the user to define any // NOTE: defining this as a loop will enable the user to define any
// of the aliases as the handler and thus breaking the loop... // of the aliases as the handler and thus breaking the loop...
// NOTE: unless the loop is broken this set of options is not usable. // NOTE: unless the loop is broken this set of options is not usable.
'-v': '-verbose', //'-v': '-verbose',
'-verbose': '-v', //'-verbose': '-v',
// Handle arguments with no explicit handlers found... // Handle arguments with no explicit handlers found...
@ -404,11 +433,10 @@ object.Constructor('Parser', {
// post parsing callbacks... // post parsing callbacks...
// //
// .then(callback(unhandleed, root_value)) // .then(callback(unhandleed, root_value, rest))
// //
// .stop(callback(arg)) // .stop(callback(arg, rest))
// // .error(callback(arg, rest))
// .error(callback(arg))
// //
then: afterCallback('parsing'), then: afterCallback('parsing'),
stop: afterCallback('stop'), stop: afterCallback('stop'),
@ -479,12 +507,12 @@ object.Constructor('Parser', {
...(value ? [value] : [])) ...(value ? [value] : []))
// handle .STOP / .ERROR // handle .STOP / .ERROR
if(res === module.STOP || res === module.ERROR){ if(res === module.STOP || res === module.ERROR){
afterCallbackCall( that[res === module.STOP ?
res === module.STOP ? 'stop' : 'error', 'stop'
this, arg) : 'error'](arg, rest)
res === module.ERROR res === module.ERROR
&& this.handleErrorExit && that.handleErrorExit
&& this.handleErrorExit(arg) } && that.handleErrorExit(arg) }
return res } return res }
// NOTE: if successful this needs to modify the arg, thus it // NOTE: if successful this needs to modify the arg, thus it
// returns both the new first arg and the handler... // returns both the new first arg and the handler...
@ -545,7 +573,8 @@ object.Constructor('Parser', {
: this } : this }
continue } continue }
// unhandled... // unhandled...
unhandled.push(arg) } arg
&& unhandled.push(arg) }
// call env handlers that were not explicitly called yet... // call env handlers that were not explicitly called yet...
typeof(process) != 'unhandled' typeof(process) != 'unhandled'
&& this.envOptions() && this.envOptions()
@ -557,9 +586,7 @@ object.Constructor('Parser', {
root_value = root_value && this.handleArgumentValue ? root_value = root_value && this.handleArgumentValue ?
this.handleArgumentValue(this, root_value) this.handleArgumentValue(this, root_value)
: root_value : root_value
afterCallbackCall('parsing', this, unhandled, root_value) return this.then(unhandled, root_value, rest) },
return this },
// NOTE: see general doc... // NOTE: see general doc...
__init__: function(spec){ __init__: function(spec){

View File

@ -56,9 +56,6 @@ argv.Parser({
}).then(function(){ }).then(function(){
console.log('NESTED DONE', ...arguments) }), console.log('NESTED DONE', ...arguments) }),
'-': function(){
console.log('OPTION: "-"') },
// these aliases will not get shown... // these aliases will not get shown...
// dead-end alias... // dead-end alias...
@ -77,9 +74,9 @@ argv.Parser({
.then(function(){ .then(function(){
console.log('DONE', ...arguments) }) console.log('DONE', ...arguments) })
.stop(function(){ .stop(function(){
console.log('STOP') }) console.log('STOP', ...arguments) })
.error(function(){ .error(function(){
console.log('ERROR') }) console.log('ERROR', ...arguments) })