UNPKG

13.4 kBMarkdownView Raw
1Capitano
2========
3
4[![npm version](https://badge.fury.io/js/capitano.svg)](http://badge.fury.io/js/capitano)
5[![dependencies](https://david-dm.org/resin-io/capitano.png)](https://david-dm.org/username/repo.png)
6[![Build Status](https://travis-ci.org/resin-io/capitano.svg?branch=master)](https://travis-ci.org/resin-io/capitano)
7
8Capitano allows you to craft powerful command line applications, your way.
9
10```coffee
11capitano = require('capitano')
12
13capitano.permission 'jviotti', (done) ->
14 return done() if process.env.USER is 'jviotti'
15 done(new Error('You are not jviotti!'))
16
17capitano.command
18 signature: 'utils print <title> [words...]'
19 options: [
20 signature: 'date'
21 boolean: true
22 alias: [ 'd' ]
23 ]
24 permission: 'jviotti'
25 action: (params, options) ->
26 log = ''
27
28 if options.date
29 log += "#{new Date()} "
30
31 log += "#{params.title}: #{params.words}"
32
33 console.log(log)
34
35capitano.run process.argv, (error) ->
36 throw error if error?
37```
38
39***
40
41```sh
42$ myCoolApp utils print Error Something very bad happened
43Error: Something very bad happened
44
45$ myCoolApp utils print Error Something very bad happened -d
46Thu Dec 18 2014 14:49:27 GMT-0400 (BOT) Error: Something very bad happened
47```
48
49We wrote Capitano as we couldn't find any NodeJS command line parser that met our needs. Alternatives such as [commander.js](https://github.com/tj/commander.js), albeit being very good, didn't have good support for features such as infinitely nested git-like subcommands, per-command options and complete customisation. Capitano is our attempt at creating a non opitionated command line parser that can do everything you can imagine.
50
51Features
52--------
53
54- Infinitely nested git-like subcommands.
55- Global and per-command options.
56- Variadic arguments.
57- Option aliases.
58- Separate between parsing and executing command line arguments.
59- No built-in generated help page, you roll your own.
60- No built-in commands, you have a high degree of control over your app.
61- Permission support.
62
63Installation
64------------
65
66Install `capitano` by running:
67
68```sh
69$ npm install --save capitano
70```
71
72API
73-------
74
75## capitano.command(options)
76
77Register a command. Capitano understands the following options, but you can pass custom options to do nifty things (see the [examples section](https://github.com/resin-io/capitano#examples)):
78
79### signature (string)
80
81The command signature. If it's `*`, it will match anything that is not matched by other commands.
82
83### action (function)
84
85Function to call when the signature is matched. This function gets passed a parameter object, an options object and a `callback` to be called when the action is finished.
86
87If the `callback` argument is not declared in the action function, it'll be called implicitly, however in order to ensure Capitano works as expected, call the `callback` function if your action is async.
88
89### options ([object])
90
91Array of objects describing the options specific to this command. See the [options section](https://github.com/resin-io/capitano#option) for more information.
92
93### permission (string)
94
95Require a certain previously registered permission by name. If the permission requirements are not met, the command action will not be called and `capitano.execute()`, or `capitano.run()` will get the error you passed in from the permission function in their callbacks.
96
97Notice that Capitano doesn't currently supports passing an array of permissions. If you have that specific use case, you'll have to create a new permission that combines the other ones.
98
99## capitano.globalOption(options)
100
101Register a global option, which will be accessible from every command (and from outside too!) so be careful about naming collisions!
102
103It accepts an object containing the following options:
104
105### signature (string)
106
107The option signature **excluding** any parameter (`foo` instead of `foo <bar>`).
108
109### boolean (boolean)
110
111Whether the option is boolean (doesn't accepts any parameters). It defaults to `false`. If `parameter` is defined, then `boolean` should be `false`.
112
113### parameter (string)
114
115The name of the parameter, excluding required/optional tags (`bar` instead of `<bar>`). Notice that if you set `boolean: true`, then you have to omit this option.
116
117### alias (string|[string])
118
119Define an alias, or a set of alias for an option. Aliases can contain single letter abbreviations (`f`, `l`) or full option names (`baz`, `foo`).
120
121## capitano.permission(name, function)
122
123It registers a permission function under a certain name. The permission function is passed a `done()` function that accepts an error instance in case the user doesn't fits the permission requirements. Pass nothing if the permission requirement was matched.
124
125**Note:** You must call the `done()` function, even if your permission function is synchronous, in order for Capitano to continue.
126
127## capitano.run(argv, callback)
128
129Run and execute the application given a set of arguments (usually `process.argv`):
130
131```coffee
132capitano.run(process.argv)
133```
134
135**Note:** `capitano.run` is a shorcut function for `capitano.execute(capitano.parse(argv), callback)`. You will usually use this function, however you can use `parse()` and `execute()` in particular situations when you need to differenciate between parsing and executing the commands.
136
137## capitano.parse(argv)
138
139Parse, but not execute the command line arguments (usually `process.argv`).
140
141It returns a `cli` object containing three fields:
142
143### command (string)
144
145A string representing the issued command, omitting any option.
146
147### options (object)
148
149An object containing the raw representation of the given options.
150
151### globals (object)
152
153An object containing the matches and parsed global options.
154
155## capitano.execute(cli, callback)
156
157It accepts a `cli` object (returned by [capitano.parse()](https://github.com/resin-io/capitano#capitanoparseargv)) and
158executes the corresponding command, with it's corresponding options.
159
160You're expected to provide your own error handling mechanism here, or in the `capitano.run` if executing from there.
161
162## capitano.state
163
164An object containing the current registered commands an options. As with Capitano you're expected to implement every command (including `help`, etc) this object comes handy to accomplish a wide range of tasks.
165
166It includes the following fields:
167
168### commands (array)
169
170An array containing every registered command so far (with `capitano.command()`)
171
172See the [Command class](https://github.com/resin-io/capitano#command) for more information.
173
174### globalOptions (array)
175
176An array containing every registered global option so far (with `capitano.globalOption()`).
177
178See the [Option class](https://github.com/resin-io/capitano#option) for more information.
179
180### findCommandBySignature(signature)
181
182A self explanatory function that returns a command that matches a specific signature.
183
184### getMatchCommand(signature)
185
186Get command that matches a signature, without taking parameters into account.
187
188This means that a command `app create <id>` will be matched by a signature `app create`.
189
190## capitano.defaults
191
192An object containing some settings used by Capitano.
193
194It includes the following fields:
195
196- `signatures.wildcard (string)` The wildcard symbol. Defaults to `*`.
197- `actions.commandNotFound(signature)` The function called when a command was not found. By default, it prints a boring `Command not found: <signature>` and exits with an error code 1.
198
199**Pro tip:** If you want to modify these settings, do it as early as possible (before registering any commands/global options) as some settings are used when performing the mentioned tasks.
200
201Classes
202-------
203
204### Command
205
206The Capitano Command class contains the following public fields:
207
208#### Command#signature (Signature)
209
210See the [Signature class](https://github.com/resin-io/capitano#signature).
211
212#### Command#options ([Option])
213
214An array of [Option classes](https://github.com/resin-io/capitano#option).
215
216#### Command#isWildcard()
217
218A predicate method that returns `true` if a command represents a wildcard.
219
220***
221
222### Signature
223
224The Capitano Signature class contains the following public fields:
225
226#### Signature#hasParameters()
227
228A predicate method that returns `true` if the signature has at least one parameter.
229
230#### Signature#hasVariadicParameters()
231
232A predicate method that returns `true` if the signature has at least one variadic parameter.
233
234#### Signature#isWildcard()
235
236A predicate method that returns `true` if the signature represents a wildcard.
237
238***
239
240### Option
241
242The Capitano Option class contains the following public fields:
243
244#### Option#signature
245
246See [Signature class](https://github.com/resin-io/capitano#signature).
247
248#### Option#alias (string|[string])
249
250A string or array of string alias.
251
252#### Option#boolean (boolean)
253
254Whether the option is boolean or not.
255
256#### Option#parameter (string)
257
258An option parameter (optional).
259
260#### Option#required (boolean|string)
261
262Defines whether an option is required. If the field is `true`, a generic error is thrown, otherwise you can set a custom error message by setting to a `string`.
263
264Examples
265--------
266
267Capitano is very flexible, allowing you to implement all sort of crazy stuff. Here I present some common patterns that I've been doing on Capitano. If you have an interesting idea that you think it's worth to share, please submit a PR!
268
269### Generated help
270
271Notice this is a very rudimentary help page and lacks features such as printing global options, command specific options, handling correct aligment, etc, but you can at least get an idea on how to implement this for yourself.
272
273```coffee
274capitano = require('capitano')
275
276capitano.command
277 signature: 'version'
278 description: 'output version information'
279 action: ...
280
281capitano.command
282 signature: 'help'
283 description: 'output general help page'
284 action: ->
285 console.log("Usage: #{myAppName} [COMMANDS] [OPTIONS]")
286 console.log('\nCommands:\n')
287
288 for command in capitano.state.commands
289 continue if command.isWildcard()
290 console.log("\t#{command.signature}\t\t\t"#{command.description})
291
292capitano.run process.argv, (error) ->
293 throw error if error?
294```
295
296***
297
298```sh
299$ app help
300Usage: MyCoolApp [COMMANDS] [OPTIONS]
301
302Commands:
303
304 version output version information
305 help output general help page
306```
307
308### Command specific help pages
309
310```coffee
311capitano = require('capitano')
312
313capitano.command
314 signature: 'version'
315 description: 'output version information'
316 help: '''
317 Software versioning is the process of assigning either unique version names or unique version numbers to unique states of computer software. Within a given version number category (major, minor), these numbers are generally assigned in increasing order and correspond to new developments in the software. At a fine-grained level, revision control is often used for keeping track of incrementally different versions of electronic information, whether or not this information is computer software.
318 '''
319 action: ...
320
321capitano.command
322 signature: 'help [command...]'
323 description: 'output general help page'
324 action: (params) ->
325 return outputGeneralHelp() if not params?
326
327 command = capitano.state.getMatchCommand(params.command)
328 if not command? or command.isWildcard()
329 return capitano.defaults.actions.commandNotFound(params.command)
330
331 console.log(command.help)
332
333capitano.run process.argv, (error) ->
334 throw error if error?
335```
336
337***
338
339```sh
340$ app help version
341Software versioning is the process of assigning either unique version names or unique version numbers to unique states of computer software. Within a given version number category (major, minor), these numbers are generally assigned in increasing order and correspond to new developments in the software. At a fine-grained level, revision control is often used for keeping track of incrementally different versions of electronic information, whether or not this information is computer software.
342```
343
344Tests
345-----
346
347Run the test suite by doing:
348
349```sh
350$ gulp test
351```
352
353ChangeLog
354---------
355
356### 1.3.1
357
358- Catch action errors and send them to the callback automatically. See [#17](https://github.com/resin-io/capitano/pull/17).
359
360### 1.3.0
361
362- Implement permission support. Discussed in [#15](https://github.com/resin-io/capitano/issues/15).
363
364### 1.2.0
365
366- Implement action callback support. Discussed in [#11](https://github.com/resin-io/capitano/issues/11).
367
368### 1.1.1
369
370- Fix issue with parsing words that start with a number.
371
372### 1.1.0
373
374- Implement support for required options.
375
376### 1.0.4
377
378- Fix issue when instantiating Parameter instances with a number directly.
379
380### 1.0.3
381
382- Fix issue with quotation of multi word parameters. Thanks [@Page-](https://github.com/Page-)!
383
384### 1.0.2
385
386- Fix https://github.com/resin-io/capitano/issues/4.
387
388### 1.0.1
389
390- Fix issues with path and quoted multi string parameters.
391
392Contribute
393----------
394
395- Issue Tracker: [github.com/resin-io/capitano/issues](https://github.com/resin-io/capitano/issues)
396- Source Code: [github.com/resin-io/capitano](https://github.com/resin-io/capitano)
397
398Before submitting a PR, please make sure that you include tests, and that [coffeelint](http://www.coffeelint.org/) runs without any warning:
399
400```sh
401$ gulp lint
402```
403
404Support
405-------
406
407If you're having any problem, please [raise an issue](https://github.com/resin-io/capitano/issues) on GitHub.
408
409TODO
410-------
411
412- Options default values.
413- Allow comma-separated parameter values (numbers, floats, etc).
414
415License
416-------
417
418The project is licensed under the MIT license.