UNPKG

13.4 kBMarkdownView Raw
1<img width="945" alt="2017-07-26 9 27 05" src="https://user-images.githubusercontent.com/8784712/28623641-373450f4-7249-11e7-854d-1b076dab274d.png">
2
3[![NPM version](https://img.shields.io/npm/v/cac.svg?style=flat)](https://npmjs.com/package/cac) [![NPM downloads](https://img.shields.io/npm/dm/cac.svg?style=flat)](https://npmjs.com/package/cac) [![CircleCI](https://circleci.com/gh/cacjs/cac/tree/master.svg?style=shield)](https://circleci.com/gh/cacjs/cac/tree/master) [![Codecov](https://badgen.net/codecov/c/github/cacjs/cac/master)](https://codecov.io/gh/cacjs/cac) [![donate](https://img.shields.io/badge/$-donate-ff69b4.svg?maxAge=2592000&style=flat)](https://github.com/egoist/donate) [![chat](https://img.shields.io/badge/chat-on%20discord-7289DA.svg?style=flat)](https://chat.egoist.moe) [![install size](https://badgen.net/packagephobia/install/cac)](https://packagephobia.now.sh/result?p=cac)
4
5## Introduction
6
7**C**ommand **A**nd **C**onquer is a JavaScript library for building CLI apps.
8
9## Features
10
11- **Super light-weight**: No dependency, just a single file.
12- **Easy to learn**. There're only 4 APIs you need to learn for building simple CLIs: `cli.option` `cli.version` `cli.help` `cli.parse`.
13- **Yet so powerful**. Enable features like default command, git-like subcommands, validation for required arguments and options, variadic arguments, dot-nested options, automated help message generation and so on.
14- **Developer friendly**. Written in TypeScript.
15
16## Table of Contents
17
18<!-- toc -->
19
20- [Install](#install)
21- [Usage](#usage)
22 - [Simple Parsing](#simple-parsing)
23 - [Display Help Message and Version](#display-help-message-and-version)
24 - [Command-specific Options](#command-specific-options)
25 - [Brackets](#brackets)
26 - [Variadic Arguments](#variadic-arguments)
27 - [Dot-nested Options](#dot-nested-options)
28 - [Default Command](#default-command)
29 - [Supply an array as option value](#supply-an-array-as-option-value)
30 - [With TypeScript](#with-typescript)
31- [Projects Using CAC](#projects-using-cac)
32- [References](#references)
33 - [CLI Instance](#cli-instance)
34 - [cac(name?)](#cacname)
35 - [cli.command(name, description, config?)](#clicommandname-description-config)
36 - [cli.option(name, description, config?)](#clioptionname-description-config)
37 - [cli.parse(argv?)](#cliparseargv)
38 - [cli.version(version, customFlags?)](#cliversionversion-customflags)
39 - [cli.help(callback?)](#clihelpcallback)
40 - [cli.outputHelp(subCommand?)](#clioutputhelpsubcommand)
41 - [Command Instance](#command-instance)
42 - [command.option()](#commandoption)
43 - [command.action(callback)](#commandactioncallback)
44 - [command.alias(name)](#commandaliasname)
45 - [command.allowUnknownOptions()](#commandallowunknownoptions)
46 - [command.example(example)](#commandexampleexample)
47 - [Events](#events)
48- [FAQ](#faq)
49 - [How is the name written and pronounced?](#how-is-the-name-written-and-pronounced)
50 - [Why not use Commander.js?](#why-not-use-commanderjs)
51- [Contributing](#contributing)
52- [Author](#author)
53
54<!-- tocstop -->
55
56## Install
57
58```bash
59yarn add cac
60```
61
62## Usage
63
64### Simple Parsing
65
66Use CAC as simple argument parser:
67
68```js
69// examples/basic-usage.js
70const cli = require('cac')()
71
72cli.option('--type [type]', 'Choose a project type', {
73 default: 'node'
74})
75
76const parsed = cli.parse()
77
78console.log(JSON.stringify(parsed, null, 2))
79```
80
81<img width="500" alt="2018-11-26 12 28 03" src="https://user-images.githubusercontent.com/8784712/48981576-2a871000-f112-11e8-8151-80f61e9b9908.png">
82
83### Display Help Message and Version
84
85```js
86// examples/help.js
87const cli = require('cac')()
88
89cli.option('--type [type]', 'Choose a project type', {
90 default: 'node'
91})
92cli.option('--name <name>', 'Provide your name')
93
94cli.command('lint [...files]', 'Lint files').action((files, options) => {
95 console.log(files, options)
96})
97
98// Display help message when `-h` or `--help` appears
99cli.help()
100// Display version number when `-h` or `--help` appears
101cli.version('0.0.0')
102
103cli.parse()
104```
105
106<img width="500" alt="2018-11-25 8 21 14" src="https://user-images.githubusercontent.com/8784712/48979012-acb20d00-f0ef-11e8-9cc6-8ffca00ab78a.png">
107
108### Command-specific Options
109
110You can attach options to a command.
111
112```js
113const cli = require('cac')()
114
115cli
116 .command('rm <dir>', 'Remove a dir')
117 .option('-r, --recursive', 'Remove recursively')
118 .action((dir, options) => {
119 console.log('remove ' + dir + (options.recursive ? ' recursively' : ''))
120 })
121
122cli.help()
123
124cli.parse()
125```
126
127A command's options are validated when the command is used. Any unknown options will be reported as an error. However, if an action-based command does not define an action, then the options are not validated. If you really want to use unknown options, use [`command.allowUnknownOptions`](#commandallowunknownoptions).
128
129<img alt="command options" width="500" src="https://user-images.githubusercontent.com/8784712/49065552-49dc8500-f259-11e8-9c7b-a7c32d70920e.png">
130
131### Brackets
132
133When using brackets in command name, angled brackets indicate required command arguments, while sqaure bracket indicate optional arguments.
134
135When using brackets in option name, angled brackets indicate that the option value is required, while sqaure bracket indicate that the value is optional.
136
137```js
138const cli = require('cac')()
139
140cli
141 .command('deploy <folder>', 'Deploy a folder to AWS')
142 .option('--scale [level]', 'Scaling level')
143 .action((folder, options) => {
144 console.log(folder)
145 console.log(options)
146 })
147
148cli.parse()
149```
150
151### Variadic Arguments
152
153The last argument of a command can be variadic, and only the last argument. To make an argument variadic you have to add `...` to the start of argument name, just like the rest operator in JavaScript. Here is an example:
154
155```js
156const cli = require('cac')()
157
158cli
159 .command('build <entry> [...otherFiles]', 'Build your app')
160 .option('--foo', 'Foo option')
161 .action((entry, otherFiles, options) => {
162 console.log(entry)
163 console.log(otherFiles)
164 console.log(options)
165 })
166
167cli.help()
168
169cli.parse()
170```
171
172<img width="500" alt="2018-11-25 8 25 30" src="https://user-images.githubusercontent.com/8784712/48979056-47125080-f0f0-11e8-9d8f-3219e0beb0ed.png">
173
174### Dot-nested Options
175
176Dot-nested options will be merged into a single option.
177
178```js
179const cli = require('cac')()
180
181cli
182 .command('build', 'desc')
183 .option('--env <env>', 'Set envs')
184 .example('--env.API_SECRET xxx')
185 .action(options => {
186 console.log(options)
187 })
188
189cli.help()
190
191cli.parse()
192```
193
194<img width="500" alt="2018-11-25 9 37 53" src="https://user-images.githubusercontent.com/8784712/48979771-6ada9400-f0fa-11e8-8192-e541b2cfd9da.png">
195
196### Default Command
197
198Register a command that will be used when no other command is matched.
199
200```js
201const cli = require('cac')()
202
203cli
204 // Simply omit the command name, just brackets
205 .command('[...files]', 'Build files')
206 .option('--minimize', 'Minimize output')
207 .action((files, options) => {
208 console.log(files)
209 console.log(options.minimize)
210 })
211
212cli.parse()
213```
214
215### Supply an array as option value
216
217```bash
218node cli.js --include project-a
219# The parsed options will be:
220# { include: 'project-a' }
221
222node cli.js --include project-a --include project-b
223# The parsed options will be:
224# { include: ['project-a', 'project-b'] }
225```
226
227### With TypeScript
228
229First you need `@types/node` to be installed as a dev dependency in your project:
230
231```bash
232yarn add @types/node --dev
233```
234
235Then everything just works out of the box:
236
237```js
238const cac = require('cac')
239// OR ES modules
240import * as cac from 'cac'
241```
242
243## Projects Using CAC
244
245Projects that use **CAC**:
246
247- [VuePress](https://github.com/vuejs/vuepress): :memo: Minimalistic Vue-powered static site generator.
248- [SAO](https://github.com/egoist/sao): ⚔️ Futuristic scaffolding tool.
249- [DocPad](https://github.com/docpad/docpad): 🏹 Powerful Static Site Generator.
250- [Poi](https://github.com/egoist/poi): ⚡️ Delightful web development.
251- [bili](https://github.com/egoist/bili): 🥂 Schweizer Armeemesser for bundling JavaScript libraries.
252- [lass](https://github.com/lassjs/lass): 💁🏻 Scaffold a modern package boilerplate for Node.js.
253- [Foy](https://github.com/zaaack/foy): 🏗 A lightweight and modern task runner and build tool for general purpose.
254- Feel free to add yours here...
255
256## References
257
258**💁 Check out [the generated docs](https://cac-api-doc.egoist.sh/classes/_cac_.cac.html) from source code if you want a more in-depth API references.**
259
260Below is a brief overview.
261
262### CLI Instance
263
264CLI instance is created by invoking the `cac` function:
265
266```js
267const cac = require('cac')
268const cli = cac()
269```
270
271#### cac(name?)
272
273Create a CLI instance, optionally specify the program name which will be used to display in help and version message. When not set we use the basename of `argv[1]`.
274
275#### cli.command(name, description, config?)
276
277- Type: `(name: string, description: string) => Command`
278
279Create a command instance.
280
281The option also accepts a third argument `config` for addtional command config:
282
283- `config.allowUnknownOptions`: `boolean` Allow unknown options in this command.
284- `config.ignoreOptionDefaultValue`: `boolean` Don't use the options's default value in parsed options, only display them in help message.
285
286#### cli.option(name, description, config?)
287
288- Type: `(name: string, description: string, config?: OptionConfig) => CLI`
289
290Add a global option.
291
292The option also accepts a third argument `config` for addtional option config:
293
294- `config.default`: Default value for the option.
295
296#### cli.parse(argv?)
297
298- Type: `(argv = process.argv) => ParsedArgv`
299
300```ts
301interface ParsedArgv {
302 args: string[]
303 options: {
304 [k: string]: any
305 }
306}
307```
308
309When this method is called, `cli.rawArgs` `cli.args` `cli.options` `cli.matchedCommand` will also be available.
310
311#### cli.version(version, customFlags?)
312
313- Type: `(version: string, customFlags = '-v, --version') => CLI`
314
315Output version number when `-v, --version` flag appears.
316
317#### cli.help(callback?)
318
319- Type: `(callback?: HelpCallback) => CLI`
320
321Output help message when `-h, --help` flag appears.
322
323Optional `callback` allows post-processing of help text before it is displayed:
324
325```ts
326type HelpCallback = (sections: HelpSection[]) => void
327
328interface HelpSection {
329 title?: string
330 body: string
331}
332```
333
334#### cli.outputHelp(subCommand?)
335
336- Type: `(subCommand?: boolean) => CLI`
337
338Output help message. Optional `subCommand` argument if you want to output the help message for the matched sub-command instead of the global help message.
339
340### Command Instance
341
342Command instance is created by invoking the `cli.command` method:
343
344```js
345const command = cli.command('build [...files]', 'Build given files')
346```
347
348#### command.option()
349
350Basically the same as `cli.option` but this adds the option to specific command.
351
352#### command.action(callback)
353
354- Type: `(callback: ActionCallback) => Command`
355
356Use a callback function as the command action when the command matches user inputs.
357
358```ts
359type ActionCallback = (
360 // Parsed CLI args
361 // The last arg will be an array if it's an varadic argument
362 ...args: string | string[] | number | number[]
363 // Parsed CLI options
364 options: Options
365) => any
366
367interface Options {
368 [k: string]: any
369}
370```
371
372#### command.alias(name)
373
374- Type: `(name: string) => Command`
375
376Add an alias name to this command, the `name` here can't contain brackets.
377
378#### command.allowUnknownOptions()
379
380- Type: `() => Command`
381
382Allow unknown options in this command, by default CAC will log an error when unknown options are used.
383
384#### command.example(example)
385
386- Type: `(example: CommandExample) => Command`
387
388Add an example which will be displayed at the end of help message.
389
390```ts
391type CommandExample = ((name: string) => string) | string
392```
393
394### Events
395
396Listen to commands:
397
398```js
399// Listen to the `foo` command
400cli.on('command:foo', () => {
401 // Do something
402})
403
404// Listen to the default command
405cli.on('command:!', () => {
406 // Do something
407})
408
409// Listen to unknown commands
410cli.on('command:*', () => {
411 console.error('Invalid command: %', cli.args.join(' '))
412 process.exit(1)
413})
414```
415
416## FAQ
417
418### How is the name written and pronounced?
419
420CAC, or cac, pronounced `C-A-C`.
421
422This project is dedicated to our lovely C.C. sama. Maybe CAC stands for C&C as well :P
423
424<img src="http://i.giphy.com/v3FeH4swox9mg.gif" width="400"/>
425
426### Why not use Commander.js?
427
428CAC is very similar to Commander.js, while the latter does not support dot nested options, i.e. something like `--env.API_SECRET foo`. Besides, you can't use unknown options in Commander.js either.
429
430_And maybe more..._
431
432Basically I made CAC to fulfill my own needs for building CLI apps like [Poi](https://poi.js.org), [SAO](https://saojs.org) and all my CLI apps. It's small, simple but powerful :P
433
434## Contributing
435
4361. Fork it!
4372. Create your feature branch: `git checkout -b my-new-feature`
4383. Commit your changes: `git commit -am 'Add some feature'`
4394. Push to the branch: `git push origin my-new-feature`
4405. Submit a pull request :D
441
442## Author
443
444**CAC** © [EGOIST](https://github.com/egoist), Released under the [MIT](./LICENSE) License.<br>
445Authored and maintained by egoist with help from contributors ([list](https://github.com/cacjs/cac/contributors)).
446
447> [Website](https://egoist.sh) · GitHub [@egoist](https://github.com/egoist) · Twitter [@\_egoistlily](https://twitter.com/_egoistlily)