mirror of
https://github.com/flynx/argv.js.git
synced 2025-10-29 02:40:07 +00:00
migrated code from ig-object/test.js...
Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
parent
a23f2c1bc8
commit
167cbf1258
257
argv.js
Normal file
257
argv.js
Normal file
@ -0,0 +1,257 @@
|
|||||||
|
/**********************************************************************
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
**********************************************************************/
|
||||||
|
((typeof define)[0]=='u'?function(f){module.exports=f(require)}:define)
|
||||||
|
(function(require){ var module={} // make module AMD/node compatible...
|
||||||
|
/*********************************************************************/
|
||||||
|
|
||||||
|
var object = require('ig-object')
|
||||||
|
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------
|
||||||
|
|
||||||
|
module.OPTION_PATTERN = /^--?/
|
||||||
|
module.COMMAND_PATTERN = /^[a-zA-Z]/
|
||||||
|
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------
|
||||||
|
// basic argv parser...
|
||||||
|
//
|
||||||
|
// Format:
|
||||||
|
// {
|
||||||
|
// // alias...
|
||||||
|
// '-v': '-verbose',
|
||||||
|
// // handler...
|
||||||
|
// '-verbose': function(opt, rest){
|
||||||
|
// ...
|
||||||
|
// },
|
||||||
|
//
|
||||||
|
// '-t': '-test',
|
||||||
|
// '-test': {
|
||||||
|
// doc: 'test option.',
|
||||||
|
// arg: 'VALUE',
|
||||||
|
// handler: function(value, opt, rest){
|
||||||
|
// ...
|
||||||
|
// }},
|
||||||
|
//
|
||||||
|
// command: function(){
|
||||||
|
// ...
|
||||||
|
// },
|
||||||
|
// ...
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// XXX add features:
|
||||||
|
// - option groups -- nested specs...
|
||||||
|
// - arg value type conversion???
|
||||||
|
// - make this a constructor???
|
||||||
|
// - extend this to support command calling...
|
||||||
|
// XXX do we handle = for options with values???
|
||||||
|
// XXX move this to it's own lib...
|
||||||
|
// argv-handler
|
||||||
|
// ig-argv
|
||||||
|
// ...
|
||||||
|
// XXX need better test processing:
|
||||||
|
// - line breaks
|
||||||
|
// - ...
|
||||||
|
var ArgvParser =
|
||||||
|
module.ArgvParser =
|
||||||
|
function(spec){
|
||||||
|
// spec defaults...
|
||||||
|
// NOTE: this is intentionally not dynamic...
|
||||||
|
spec = Object.assign({
|
||||||
|
// builtin options...
|
||||||
|
'-h': '-help',
|
||||||
|
// XXX revise...
|
||||||
|
'-help': {
|
||||||
|
doc: 'print this message and exit.',
|
||||||
|
handler: function(){
|
||||||
|
var spec = this.spec
|
||||||
|
var that = this
|
||||||
|
var x
|
||||||
|
console.log([
|
||||||
|
`Usage: ${
|
||||||
|
typeof(spec.__usage__) == 'function' ?
|
||||||
|
spec.__usage__.call(this)
|
||||||
|
: spec.__usage__ }`,
|
||||||
|
// doc...
|
||||||
|
...(spec.__doc__ ?
|
||||||
|
['', typeof(spec.__doc__) == 'function' ?
|
||||||
|
spec.__doc__()
|
||||||
|
: spec.__doc__]
|
||||||
|
: []),
|
||||||
|
// options...
|
||||||
|
'',
|
||||||
|
'Options:',
|
||||||
|
...(spec.__getoptions__()
|
||||||
|
.map(function([opts, arg, doc]){
|
||||||
|
return [opts.join(' | -') +' '+ (arg || ''), doc] })),
|
||||||
|
// commands...
|
||||||
|
...(((x = spec.__getcommands__()) && x.length > 0) ?
|
||||||
|
['', 'Commands:',
|
||||||
|
...x.map(function([cmd, _, doc]){
|
||||||
|
return [cmd.join(' | '), doc] })]
|
||||||
|
: []),
|
||||||
|
// examples...
|
||||||
|
...(this.spec.__examples__ ?
|
||||||
|
['', 'Examples:', ...(
|
||||||
|
this.spec.__examples__ instanceof Array ?
|
||||||
|
spec.__examples__
|
||||||
|
.map(function(e){
|
||||||
|
return e instanceof Array ? e : [e] })
|
||||||
|
: spec.__examples__(this) )]
|
||||||
|
: []),
|
||||||
|
// footer...
|
||||||
|
...(this.spec.__footer__?
|
||||||
|
['', typeof(this.spec.__footer__) == 'function' ?
|
||||||
|
spec.__footer__(this)
|
||||||
|
: spec.__footer__]
|
||||||
|
: []) ]
|
||||||
|
.map(function(e){
|
||||||
|
return e instanceof Array ?
|
||||||
|
spec.__align__(...e
|
||||||
|
.map(function(s){
|
||||||
|
return s.replace(/\$scriptname/g, that.scriptname) }))
|
||||||
|
// indent lists...
|
||||||
|
.map(function(s){
|
||||||
|
return '\t'+ s })
|
||||||
|
: e })
|
||||||
|
.flat()
|
||||||
|
.join('\n')
|
||||||
|
.replace(/\$scriptname/g, this.scriptname))
|
||||||
|
|
||||||
|
process.exit() }},
|
||||||
|
|
||||||
|
// special values and methods...
|
||||||
|
__pre_check__: true,
|
||||||
|
__opt_pattern__: module.OPTION_PATTERN,
|
||||||
|
__cmd_pattern__: module.COMMAND_PATTERN,
|
||||||
|
__opts_width__: 3,
|
||||||
|
__doc_prefix__: '- ',
|
||||||
|
|
||||||
|
// these is run in the same context as the handlers... (XXX ???)
|
||||||
|
__align__: function(a, b, ...rest){
|
||||||
|
var opts_width = this.__opts_width__ || 4
|
||||||
|
var prefix = this.__doc_prefix__ || ''
|
||||||
|
b = [b, ...rest].join('\n'+ ('\t'.repeat(opts_width+1) + ' '.repeat(prefix.length)))
|
||||||
|
return b ?
|
||||||
|
(a.raw.length < opts_width*8 ?
|
||||||
|
[a +'\t'.repeat(opts_width - Math.floor(a.raw.length/8))+ prefix + b]
|
||||||
|
: [a, '\t'.repeat(opts_width)+ prefix + b])
|
||||||
|
: [a] },
|
||||||
|
|
||||||
|
__usage__: function(){
|
||||||
|
return `${ this.scriptname } [OPTIONS]` },
|
||||||
|
__doc__: undefined,
|
||||||
|
__examples__: undefined,
|
||||||
|
__footer__: undefined,
|
||||||
|
|
||||||
|
__unknown__: function(key){
|
||||||
|
console.error('Unknown option:', key)
|
||||||
|
process.exit(1) },
|
||||||
|
|
||||||
|
// these are run in the context of spec...
|
||||||
|
__getoptions__: function(...pattern){
|
||||||
|
var that = this
|
||||||
|
pattern = pattern.length == 0 ?
|
||||||
|
[this.__opt_pattern__
|
||||||
|
|| module.OPTION_PATTERN]
|
||||||
|
: pattern
|
||||||
|
return pattern
|
||||||
|
.map(function(pattern){
|
||||||
|
var handlers = {}
|
||||||
|
Object.keys(that)
|
||||||
|
.forEach(function(opt){
|
||||||
|
// skip special methods...
|
||||||
|
if(/^__.*__$/.test(opt)
|
||||||
|
|| !pattern.test(opt)){
|
||||||
|
return }
|
||||||
|
var [k, h] = that.__gethandler__(opt)
|
||||||
|
handlers[k] ?
|
||||||
|
handlers[k][0].push(opt)
|
||||||
|
: (handlers[k] = [[opt], h.arg, h.doc || k, h]) })
|
||||||
|
return Object.values(handlers) })
|
||||||
|
.flat(1) },
|
||||||
|
__iscommand__: function(str){
|
||||||
|
return (this.__cmd_pattern__
|
||||||
|
|| module.COMMAND_PATTERN)
|
||||||
|
.test(str)
|
||||||
|
&& str in this },
|
||||||
|
__getcommands__: function(){
|
||||||
|
return this.__getoptions__(
|
||||||
|
this.__cmd_pattern__
|
||||||
|
|| module.COMMAND_PATTERN) },
|
||||||
|
__gethandler__: function(key){
|
||||||
|
key = key.replace(
|
||||||
|
this.__opt_pattern__
|
||||||
|
|| module.OPTION_PATTERN,
|
||||||
|
'-')
|
||||||
|
var seen = new Set([key])
|
||||||
|
while(key in this
|
||||||
|
&& typeof(this[key]) == typeof('str')){
|
||||||
|
key = this[key]
|
||||||
|
// check for loops...
|
||||||
|
if(seen.has(key)){
|
||||||
|
throw Error('Option loop detected: '+ ([...seen, key].join(' -> '))) }
|
||||||
|
seen.add(key) }
|
||||||
|
return [key, this[key]] },
|
||||||
|
}, spec)
|
||||||
|
|
||||||
|
// sanity check -- this will detect argument loops for builtin opts
|
||||||
|
// and commands...
|
||||||
|
spec.__pre_check__
|
||||||
|
&& spec.__getoptions__(
|
||||||
|
spec.__opt_pattern__ || module.OPTION_PATTERN,
|
||||||
|
spec.__cmd_pattern__ || module.COMMAND_PATTERN)
|
||||||
|
|
||||||
|
return function(argv){
|
||||||
|
var opt_pattern = spec.__opt_pattern__
|
||||||
|
|| module.OPTION_PATTERN
|
||||||
|
argv = argv.slice()
|
||||||
|
var context = {
|
||||||
|
spec: spec,
|
||||||
|
argv: argv.slice(),
|
||||||
|
|
||||||
|
interpreter: argv.shift(),
|
||||||
|
script: argv[0],
|
||||||
|
scriptname: argv.shift().split(/[\\\/]/).pop(),
|
||||||
|
|
||||||
|
rest: argv,
|
||||||
|
}
|
||||||
|
var other = []
|
||||||
|
while(argv.length > 0){
|
||||||
|
var arg = argv.shift()
|
||||||
|
var type = opt_pattern.test(arg) ?
|
||||||
|
'opt'
|
||||||
|
: spec.__iscommand__(arg) ?
|
||||||
|
'cmd'
|
||||||
|
: 'other'
|
||||||
|
// options / commands...
|
||||||
|
if(type != 'other'){
|
||||||
|
// get handler...
|
||||||
|
var handler = spec.__gethandler__(arg).pop()
|
||||||
|
|| spec.__unknown__
|
||||||
|
// get option value...
|
||||||
|
var value = (handler.arg && !opt_pattern.test(argv[0])) ?
|
||||||
|
argv.shift()
|
||||||
|
: undefined
|
||||||
|
// run handler...
|
||||||
|
;(typeof(handler) == 'function' ?
|
||||||
|
handler
|
||||||
|
: handler.handler)
|
||||||
|
.call(context,
|
||||||
|
// pass value...
|
||||||
|
...(handler.arg ? [value] : []),
|
||||||
|
arg,
|
||||||
|
argv)
|
||||||
|
continue }
|
||||||
|
// other...
|
||||||
|
other.push(arg) }
|
||||||
|
return other } }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**********************************************************************
|
||||||
|
* vim:set ts=4 sw=4 : */ return module })
|
||||||
28
package.json
Normal file
28
package.json
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
{
|
||||||
|
"name": "ig-argv",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "simple argv parser",
|
||||||
|
"main": "argv.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "node ./test.js"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git+https://github.com/flynx/argv.js.git"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"javascript",
|
||||||
|
"argv",
|
||||||
|
"parser",
|
||||||
|
"commandline"
|
||||||
|
],
|
||||||
|
"author": "Alex A. Naanou <alex.nanou@gmail.com>",
|
||||||
|
"license": "BSD-3-Clause",
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/flynx/argv.js/issues"
|
||||||
|
},
|
||||||
|
"homepage": "https://github.com/flynx/argv.js#readme",
|
||||||
|
"dependencies": {
|
||||||
|
"ig-object": "^5.0.8"
|
||||||
|
}
|
||||||
|
}
|
||||||
24
test.js
Normal file
24
test.js
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
/**********************************************************************
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
**********************************************************************/
|
||||||
|
((typeof define)[0]=='u'?function(f){module.exports=f(require)}:define)
|
||||||
|
(function(require){ var module={} // make module AMD/node compatible...
|
||||||
|
/*********************************************************************/
|
||||||
|
|
||||||
|
var colors = require('colors')
|
||||||
|
var object = require('ig-object')
|
||||||
|
|
||||||
|
var argv = require('./argv')
|
||||||
|
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**********************************************************************
|
||||||
|
* vim:set ts=4 sw=4 : */ return module })
|
||||||
Loading…
x
Reference in New Issue
Block a user