1 var assert = require('assert'),
2 path = require('path'),
3 Completion = require('./lib/completion'),
4 Parser = require('./lib/parser'),
5 Usage = require('./lib/usage'),
6 Validation = require('./lib/validation')
8 Argv(process.argv.slice(2))
10 var exports = module.exports = Argv
11 function Argv (processArgs, cwd) {
12 processArgs = processArgs || [] // handle calling yargs().
19 if (!cwd) cwd = process.cwd()
21 self.$0 = process.argv
23 .map(function (x, i) {
24 // ignore the node bin, specify this in your
25 // bin file with #!/usr/bin/env node
26 if (i === 0 && /\b(node|iojs)$/.test(x)) return
27 var b = rebase(cwd, x)
28 return x.match(/^\//) && b.length < x.length
33 if (process.env._ !== undefined && process.argv[1] === process.env._) {
34 self.$0 = process.env._.replace(
35 path.dirname(process.execPath) + '/', ''
40 self.resetOptions = self.reset = function () {
41 // put yargs back into its initial
42 // state, this is useful for creating a
52 defaultDescription: {},
59 usage = Usage(self) // handle usage output.
60 validation = Validation(self, usage) // handle arg validation.
61 completion = Completion(self, usage)
77 self.boolean = function (bools) {
78 options.boolean.push.apply(options.boolean, [].concat(bools))
82 self.array = function (arrays) {
83 options.array.push.apply(options.array, [].concat(arrays))
87 self.nargs = function (key, n) {
88 if (typeof key === 'object') {
89 Object.keys(key).forEach(function (k) {
98 self.normalize = function (strings) {
99 options.normalize.push.apply(options.normalize, [].concat(strings))
103 self.config = function (configs) {
104 options.config.push.apply(options.config, [].concat(configs))
108 self.example = function (cmd, description) {
109 usage.example(cmd, description)
113 self.command = function (cmd, description, fn) {
114 usage.command(cmd, description)
115 if (fn) commandHandlers[cmd] = fn
119 var commandHandlers = {}
120 self.getCommandHandlers = function () {
121 return commandHandlers
124 self.string = function (strings) {
125 options.string.push.apply(options.string, [].concat(strings))
129 self.default = function (key, value, defaultDescription) {
130 if (typeof key === 'object') {
131 Object.keys(key).forEach(function (k) {
132 self.default(k, key[k])
135 if (typeof value === 'function') {
136 defaultDescription = usage.functionDescription(value, defaultDescription)
139 options.defaultDescription[key] = defaultDescription
140 options.default[key] = value
145 self.alias = function (x, y) {
146 if (typeof x === 'object') {
147 Object.keys(x).forEach(function (key) {
148 self.alias(key, x[key])
151 options.alias[x] = (options.alias[x] || []).concat(y)
156 self.count = function (counts) {
157 options.count.push.apply(options.count, [].concat(counts))
162 self.demand = self.required = self.require = function (keys, msg) {
163 if (typeof keys === 'number') {
164 if (!demanded._) demanded._ = { count: 0, msg: null }
165 demanded._.count += keys
167 } else if (Array.isArray(keys)) {
168 keys.forEach(function (key) {
169 self.demand(key, msg)
172 if (typeof msg === 'string') {
173 demanded[keys] = { msg: msg }
174 } else if (msg === true || typeof msg === 'undefined') {
175 demanded[keys] = { msg: undefined }
181 self.getDemanded = function () {
185 self.requiresArg = function (requiresArgs) {
186 options.requiresArg.push.apply(options.requiresArg, [].concat(requiresArgs))
190 self.implies = function (key, value) {
191 validation.implies(key, value)
195 self.usage = function (msg, opts) {
196 if (!opts && typeof msg === 'object') {
203 if (opts) self.options(opts)
208 self.epilogue = self.epilog = function (msg) {
213 self.fail = function (f) {
218 self.check = function (f) {
223 self.defaults = self.default
225 self.describe = function (key, desc) {
226 options.key[key] = true
227 usage.describe(key, desc)
231 self.parse = function (args) {
232 return parseArgs(args)
235 self.option = self.options = function (key, opt) {
236 if (typeof key === 'object') {
237 Object.keys(key).forEach(function (k) {
238 self.options(k, key[k])
241 assert(typeof opt === 'object', 'second argument to option must be an object')
243 options.key[key] = true // track manually set keys.
245 if (opt.alias) self.alias(key, opt.alias)
247 var demand = opt.demand || opt.required || opt.require
250 self.demand(key, demand)
251 } if ('default' in opt) {
252 self.default(key, opt.default)
253 } if ('nargs' in opt) {
254 self.nargs(key, opt.nargs)
255 } if (opt.boolean || opt.type === 'boolean') {
257 if (opt.alias) self.boolean(opt.alias)
258 } if (opt.array || opt.type === 'array') {
260 if (opt.alias) self.array(opt.alias)
261 } if (opt.string || opt.type === 'string') {
263 if (opt.alias) self.string(opt.alias)
264 } if (opt.count || opt.type === 'count') {
268 var desc = opt.describe || opt.description || opt.desc
270 self.describe(key, desc)
273 if (opt.requiresArg) {
274 self.requiresArg(key)
280 self.getOptions = function () {
284 self.wrap = function (cols) {
290 self.strict = function () {
294 self.getStrict = function () {
298 self.showHelp = function (level) {
299 if (!self.parsed) parseArgs(processArgs) // run parser, if it has not already been executed.
300 usage.showHelp(level)
304 var versionOpt = null
305 self.version = function (ver, opt, msg) {
306 versionOpt = opt || 'version'
308 self.boolean(versionOpt)
309 self.describe(versionOpt, msg || 'Show version number')
314 self.addHelpOpt = function (opt, msg) {
317 self.describe(opt, msg || 'Show help')
321 self.showHelpOnFail = function (enabled, message) {
322 usage.showHelpOnFail(enabled, message)
326 var exitProcess = true
327 self.exitProcess = function (enabled) {
328 if (typeof enabled !== 'boolean') {
331 exitProcess = enabled
334 self.getExitProcess = function () {
338 self.help = function () {
339 if (arguments.length > 0) return self.addHelpOpt.apply(self, arguments)
341 if (!self.parsed) parseArgs(processArgs) // run parser, if it has not already been executed.
346 var completionOpt = null,
347 completionCommand = null
348 self.completion = function (cmd, desc, fn) {
349 // a function to execute when generating
350 // completions can be provided as the second
351 // or third argument to completion.
352 if (typeof desc === 'function') {
357 // register the completion command.
358 completionCommand = cmd
359 completionOpt = completion.completionKey
360 self.command(completionCommand, desc || 'generate bash completion script')
362 // a function can be provided
363 if (fn) completion.registerFunction(fn)
368 self.showCompletionScript = function ($0) {
370 console.log(completion.generateCompletionScript($0))
374 self.getUsageInstance = function () {
378 self.getValidationInstance = function () {
382 self.terminalWidth = function () {
383 return require('window-size').width
386 Object.defineProperty(self, 'argv', {
391 args = parseArgs(processArgs)
393 usage.fail(err.message)
401 function parseArgs (args) {
402 var parsed = Parser(args, options),
404 aliases = parsed.aliases
410 // generate a completion script for adding to ~/.bashrc.
411 if (completionCommand && ~argv._.indexOf(completionCommand)) {
412 self.showCompletionScript()
418 // if there's a handler associated with a
419 // command defer processing to it.
420 var handlerKeys = Object.keys(self.getCommandHandlers())
421 for (var i = 0, command; (command = handlerKeys[i]) !== undefined; i++) {
422 if (~argv._.indexOf(command)) {
423 self.getCommandHandlers()[command](self.reset())
428 Object.keys(argv).forEach(function (key) {
429 if (key === helpOpt && argv[key]) {
434 } else if (key === versionOpt && argv[key]) {
439 } else if (key === completionOpt) {
440 // we allow for asynchronous completions,
441 // e.g., loading in a list of commands from an API.
442 completion.getCompletion(function (completions) {
443 ;(completions || []).forEach(function (completion) {
444 console.log(completion)
455 validation.nonOptionCount(argv)
456 validation.missingArgumentValue(argv)
457 validation.requiredArguments(argv)
460 validation.unknownArguments(argv, aliases)
463 validation.customChecks(argv, aliases)
464 validation.implications(argv)
465 setPlaceholderKeys(argv)
470 function setPlaceholderKeys (argv) {
471 Object.keys(options.key).forEach(function (key) {
472 if (typeof argv[key] === 'undefined') argv[key] = undefined
480 // rebase an absolute path to a relative one with respect to a base directory
481 // exported for tests
482 exports.rebase = rebase
483 function rebase (base, dir) {
484 return path.relative(base, dir)
487 /* Hack an instance of Argv with process.argv into Argv
489 require('yargs')(['--beeble=1','-z','zizzle']).argv
490 to parse a list of args and
491 require('yargs').argv
492 to get a parsed version of process.argv.
494 function sigletonify (inst) {
495 Object.keys(inst).forEach(function (key) {
496 if (key === 'argv') {
497 Argv.__defineGetter__(key, inst.__lookupGetter__(key))
499 Argv[key] = typeof inst[key] === 'function'
500 ? inst[key].bind(inst)