mirror of
				https://github.com/flynx/argv.js.git
				synced 2025-10-31 11: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