now arguments passed correctly to merged options + doc update

Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
Alex A. Naanou 2020-07-01 13:55:52 +03:00
parent ddf141d05b
commit 5a9c087ca2
4 changed files with 44 additions and 14 deletions

View File

@ -17,12 +17,16 @@ This code is an evolution of that parser.
- Simple - Simple
- Supports both the _option_ (a-la `find`) and _command_ (a-la `git`) paradigms - Supports both the _option_ (a-la `find`) and _command_ (a-la `git`) paradigms
- Nestable &ndash; parsers can be nested as option/command handlers defining - Nestable
independent nested contexts parsers can be nested as option/command handlers defining independent
- Option expansion &ndash; `-abc` expands to `-a -b -c` if `-abc` is not defined nested contexts
- Option expansion
`-abc` expands to `-a -b -c` if `-abc` is not defined
- Option/command value passing - Option/command value passing
- Environment variable option/command values &ndash; env can control option implicit `-a 123` (requires definition or manual handling) or explicit
defaults `-a=123`
- Environment variable option/command values
env can control option defaults
- Reasonable defaults - Reasonable defaults
- `-help` generator - `-help` generator
- common option aliases - common option aliases
@ -32,6 +36,9 @@ This code is an evolution of that parser.
- Customizable error and stop condition handling - Customizable error and stop condition handling
<!-- XXX ### Alternatives -->
## Installation ## Installation
```shell ```shell

34
argv.js
View File

@ -199,10 +199,13 @@ object.Constructor('Parser', {
isCommand: function(str){ isCommand: function(str){
return this.commandInputPattern.test(str) return this.commandInputPattern.test(str)
&& (this.commandPrefix + str) in this }, && (this.commandPrefix + str) in this },
// NOTE: this ignores any arguments values present in the key...
// NOTE: this ignores options forming alias loops and dead-end // NOTE: this ignores options forming alias loops and dead-end
// options... // options...
handler: function(key){ handler: function(key){
var value // clear arg value...
key = key.split(/=/).shift()
// option or command?
key = this.optionInputPattern.test(key) ? key = this.optionInputPattern.test(key) ?
key.replace(this.optionInputPattern, this.optionPrefix+'$1') key.replace(this.optionInputPattern, this.optionPrefix+'$1')
: key.replace(this.commandInputPattern, this.commandPrefix+'$1') : key.replace(this.commandInputPattern, this.commandPrefix+'$1')
@ -231,6 +234,8 @@ object.Constructor('Parser', {
helpColumnPrefix: '- ', helpColumnPrefix: '- ',
// doc sections... // doc sections...
// XXX
version: undefined,
usage: '$SCRIPTNAME [OPTIONS]', usage: '$SCRIPTNAME [OPTIONS]',
doc: undefined, doc: undefined,
examples: undefined, examples: undefined,
@ -451,7 +456,8 @@ object.Constructor('Parser', {
var opt_pattern = this.optionInputPattern var opt_pattern = this.optionInputPattern
// helpers... // helpers...
var runHandler = function(handler, arg, value, rest){ var runHandler = function(handler, arg, rest){
var [arg, value] = arg.split(/=/)
// get option value... // get option value...
value = value value = value
|| ((handler.arg && !opt_pattern.test(rest[0])) ? || ((handler.arg && !opt_pattern.test(rest[0])) ?
@ -480,7 +486,10 @@ object.Constructor('Parser', {
&& this.handleErrorExit && this.handleErrorExit
&& this.handleErrorExit(arg) } && this.handleErrorExit(arg) }
return res } return res }
// NOTE: if successful this needs to modify the arg, thus it
// returns both the new first arg and the handler...
var splitArgs = function(arg, rest){ var splitArgs = function(arg, rest){
var [arg, value] = arg.split(/=/)
// skip single letter unknown options or '--' options... // skip single letter unknown options or '--' options...
if(arg.length <= 2 if(arg.length <= 2
|| arg.startsWith(that.optionPrefix.repeat(2))){ || arg.startsWith(that.optionPrefix.repeat(2))){
@ -489,14 +498,19 @@ object.Constructor('Parser', {
var [a, ...r] = var [a, ...r] =
[...arg.slice(1)] [...arg.slice(1)]
.map(function(e){ return '-'+ e }) .map(function(e){ return '-'+ e })
// push the value to the last arg...
value !== undefined
&& r.push(r.pop() +'='+ value)
// push new options back to option "stack"... // push new options back to option "stack"...
rest.splice(0, 0, ...r) rest.splice(0, 0, ...r)
return that.handler(a)[1] } var handler = that.handler(a)[1]
return handler
&& [a, handler] }
var env = new Set() var env = new Set()
var unhandled = [] var unhandled = []
while(rest.length > 0){ while(rest.length > 0){
var [arg, value] = rest.shift().split(/=/) var arg = rest.shift()
var type = opt_pattern.test(arg) ? var type = opt_pattern.test(arg) ?
'opt' 'opt'
: this.isCommand(arg) ? : this.isCommand(arg) ?
@ -505,18 +519,24 @@ object.Constructor('Parser', {
// options / commands... // options / commands...
if(type != 'unhandled'){ if(type != 'unhandled'){
// get handler... // get handler...
// XXX revise -- arg replacement feels clunky...
var handler = this.handler(arg)[1] var handler = this.handler(arg)[1]
// handle merged options... // handle merged options
// NOTE: if successful returns array...
|| (type == 'opt' || (type == 'opt'
&& this.splitOptions && this.splitOptions
&& splitArgs(arg, rest)) && splitArgs(arg, rest))
// dynamic/error... // dynamic or error...
|| this.handleArgument || this.handleArgument
// normalize output of splitArgs(..)
;[arg, handler] = handler instanceof Array ?
handler
: [arg, handler]
// env handler called... // env handler called...
handler.env handler.env
&& env.add(handler) && env.add(handler)
var res = runHandler(handler, arg, value, rest) var res = runHandler(handler, arg, rest)
// handle stop conditions... // handle stop conditions...
if(res === module.STOP || res === module.ERROR){ if(res === module.STOP || res === module.ERROR){

View File

@ -1,6 +1,6 @@
{ {
"name": "ig-argv", "name": "ig-argv",
"version": "2.0.5", "version": "2.0.6",
"description": "simple argv parser", "description": "simple argv parser",
"main": "argv.js", "main": "argv.js",
"scripts": { "scripts": {

View File

@ -56,6 +56,9 @@ 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...