cleanup...

Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
Alex A. Naanou 2020-07-28 03:09:12 +03:00
parent 8c4f7a6cf2
commit 9be0f4ff35
4 changed files with 51 additions and 31 deletions

View File

@ -37,6 +37,7 @@ This code is an evolution of that parser.
- Hooks for dynamic option/command handling
- Customizable error and stop condition handling
## Planned Features
- Run `<command>-<sub-command>` scripts
@ -84,7 +85,7 @@ This code is an evolution of that parser.
- [More control over help...](#more-control-over-help)
- [Nested parsers](#nested-parsers)
- [Components and API](#components-and-api)
- [`THEN`, `STOP` and `ERROR`](#then-stop-and-error)
- [`THEN`/ `STOP`](#then-stop)
- [`ParserError(..)`](#parsererror)
- [`Parser(..)`](#parser)
- [`<parser>.then(..)`](#parserthen)
@ -231,10 +232,12 @@ $ ./script.js -fb
```
## Error reporting
XXX
## XXX add subsections by task
XXX
@ -242,6 +245,7 @@ XXX
XXX might be a good idea to split out the rest to a INDETAIL.md or similar...
## Configuration
```
@ -332,9 +336,9 @@ A _value_ can be passed either explicitly passed (via `=` syntax),
implicitly parsed from the `argv` via the `<option>.arg` definition or
is `undefined` otherwise.
A handler can return one of the `THEN`, `STOP` or `ERROR` to control
further parsing and/or execution.
(See: [`THEN`, `STOP` and `ERROR`](#then-stop-and-error) for more info.)
A handler can return one of the `THEN`, `STOP` or `ParserError` instance
to control further parsing and/or execution.
(See: [`THEN` / `STOP`](#then-stop) for more info.)
#### `<option>.doc`
@ -468,6 +472,7 @@ argv.Parser.valueCollectors.Set = function(value, current, key){
Defining handlers local to a parser instance handler is the same as for
[type handlers](#optiontype) above.
#### `<option>.env`
Determines the environment variable to be used as the default value for
@ -691,26 +696,29 @@ See [lang.js](./lang.js) for more fun with argv and programming languages ;)
## Components and API
### `THEN`, `STOP` and `ERROR`
### `THEN` / `STOP`
Values that if returned by option/command handlers can control the parse flow.
- `THEN` &ndash; Stop parsing and call `<parser>.then(..)` callbacks.
- `STOP` &ndash; Stop parsing and call `<parser>.stop(..)` callbacks,
skipping `<parser>.then(..)`.
- `ERROR` &ndash; Stop parsing, call `<parser>.error(..)` callbacks and
exit with an error.
### `ParserError(..)`
A base error constructor, if an instance of `ParseError` is thrown by the
handler it has the same effect as returning `ERROR` with one difference being
that the error `.name`/`.message` will get printed.
A base error constructor.
If an instance of `ParseError` is thrown or returned by the handler parsing
is stopped, `<parsing>.error(..)` is called and then the parser will exit
with an error (see: [`<parser>.handleErrorExit(..)`](#parserhandleerrorexit)).
The following error constructors are also defined:
- `ParserTypeError(..)`
- `ParserValueError(..)`
Note that `ParserError` instances can be both returned or thrown.
### `Parser(..)`
@ -722,6 +730,7 @@ Parser(<spec>)
See [`<parser>(..)`](#parser-1) for more info.
#### `<parser>.then(..)`
Add callback to `then` "event".
@ -738,6 +747,7 @@ callback(<unhandled>, <root-value>, <rest>)
`then` is triggered when parsing is done or stopped from an option
handler by returning `THEN`.
#### `<parser>.stop(..)`
Add callback to `stop` "event".
@ -753,6 +763,7 @@ callback(<arg>, <rest>)
`stop` is triggered when a handler returns `STOP`.
#### `<parser>.error(..)`
Add callback to `error` "event".
@ -777,6 +788,7 @@ Remove callback from "event".
-> <parser>
```
#### `<parser>(..)`
Execute the `parser` instance.

42
argv.js
View File

@ -33,9 +33,8 @@ module.STOP =
module.THEN =
{doc: 'break option processing, triggers .then(..) handlers'}
module.ERROR =
{doc: 'option processing error, triggers .error(..) handlers'}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
module.ParserError =
object.Constructor('ParserError', Error, {
@ -664,8 +663,9 @@ object.Constructor('Parser', {
doc: false,
//section_doc: ...,
handler: function(_, key){
this.printError('unknown '+ (key.startsWith('-') ? 'option:' : 'command:'), key)
return module.ERROR } },
return this.printError(
module.ParserError(
`Unknown ${key.startsWith('-') ? 'option:' : 'command:'} ${ key }`)) } },
'@*': '-*',
@ -676,7 +676,18 @@ object.Constructor('Parser', {
print: afterCallback('print', null, function(...args){
console.log(...args)
return this }),
//
// .printError(...)
// -> this
//
// .printError(error, ...)
// -> error
//
printError: afterCallback('print_error', null, function(...args){
if(args[0] instanceof module.ParserError){
console.error(
this.scriptName+':', args[0].name+':', args[0].message, ...args.slice(1))
return args[0] }
console.error(this.scriptName+': Error:', ...args)
return this }),
@ -838,6 +849,12 @@ object.Constructor('Parser', {
parsed.error(reason, arg, rest)
parsed.handleErrorExit
&& parsed.handleErrorExit(arg, reason) }
var reportError = function(message, arg, rest){
message = message
.replace(/$ARG/g, arg)
handleError(message, arg, rest)
return parsed.printError(
module.ParserError(message)) }
var runHandler = function(handler, arg, rest){
var [arg, value] = arg instanceof Array ?
arg
@ -858,9 +875,7 @@ object.Constructor('Parser', {
: value
// required value check...
if(handler.valueRequired && value == null){
handleError('value missing', arg, rest)
parsed.printError('value missing:', arg+'=?')
return module.ERROR }
return reportError('Value missing: $ARG=?', arg, rest) }
try {
// run handler...
@ -880,8 +895,6 @@ object.Constructor('Parser', {
&& parsed.stop(arg, rest)
res instanceof module.ParserError
&& handleError(res, arg, rest)
res === module.ERROR
&& handleError('unknown', arg, rest)
return res }
// NOTE: if successful this needs to modify the arg, thus it
// returns both the new first arg and the handler...
@ -900,8 +913,7 @@ object.Constructor('Parser', {
&& r.push(r.pop() +'='+ value)
// push new options back to option "stack"...
rest.splice(0, 0, ...r)
var handler = parsed.handler(a)[1]
return [a, handler] }
return [ a, parsed.handler(a)[1] ] }
// parse/interpret the arguments and call handlers...
var values = new Set()
@ -936,9 +948,7 @@ object.Constructor('Parser', {
|| parsed.handler(dfl)[1]
// no handler found and '-*' or '@*' not defined...
if(handler == null){
handleError('unknown', arg, rest)
parsed.printError('unknown '+(type == 'opt' ? 'option:' : 'command:'), arg)
return module.ERROR }
return reportError(`Unknown ${ type == 'opt' ? 'option' : 'command:' } $ARG`, arg, rest) }
// mark handler...
;(handler.env || 'default' in handler)
@ -949,7 +959,6 @@ object.Constructor('Parser', {
// handle stop conditions...
if(res === module.STOP
|| res === module.ERROR
|| res instanceof module.ParserError){
return nested ?
res
@ -981,8 +990,7 @@ object.Constructor('Parser', {
.map(function([k, a, d, h]){
return k.pop() })
if(missing.length > 0){
handleError('required', missing, rest)
parsed.printError('required but missing:', missing.join(', '))
reportError('required but missing: $ARG', missing.join(', '), rest)
return parsed }
// handle root value...

View File

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

View File

@ -75,7 +75,7 @@ argv.Parser({
},
'-s': '-string',
'-string': {
doc: 'collect STR',
doc: 'collect tab-separated strings',
arg: 'STR | str',
collect: 'string|\t',
},
@ -84,13 +84,13 @@ argv.Parser({
doc: 'short option', },
'-type-error': {
doc: 'throw an type error',
doc: 'throw a type error',
type: 'error',
},
'-error': {
doc: 'throw an error',
handler: function(){
throw argv.ParserError('error') }},
return argv.ParserError('error') }},
'-test': argv.Parser({